greatest n per group multi table - php

i know there is heaps of this same question but im having trouble making it work on multiple table joins. i have 3 tables
userinfo
user_id | firstname | lastname
subnumbers
subnumber | fkuserid
transaction
transid | fksubnumber | expires | transdate
heres the part i have working
SELECT *
FROM (SELECT *
FROM subtransactions
WHERE Expires < now()
ORDER BY NewSubTrans DESC) AS s
GROUP BY FKSubNum
What i am trying to do is select all users with a subscription that is expired. to determine if a user is expired i pull the last transaction from the transaction table with thier sub number, the fk fields are the links to the other tables.

From your description, I don't think you need any group at all. Try it with just these two joins:
SELECT user_id, firstname, lastname
FROM
userinfo
JOIN subnumbers ON userinfo.user_id = subnumbers.fkuserid
JOIN transaction ON subnumbers.subnumber = transaction.fksubnumber
WHERE transaction.expires < NOW()
EDIT If it returns multiple rows as suggested in comments below, use DISTINCT in the select list:
SELECT DISTINCT user_id, firstname, lastname
-- etc...

This will get all user_ids
select distinct(user_id) from userinfo
join subnumbers on userinfo.user_id = subnumbers.fkuserid
join transaction on transaction.fksubnumber = subnumbers.subnumber
where transaction.expires < NOW()
To get full user data
select * from user where user_id in
(
select distinct(user_id) from userinfo
join subnumbers on userinfo.user_id = subnumbers.fkuserid
join transaction on transaction.fksubnumber = subnumbers.subnumber
where transaction.expires < NOW()
)

Related

top first friends then the other users from like list

I have tables:
likes - id, user_id, like_user_id<br>
users - id, name, email ...,<br>
friends - id, user_id, friend_id, status<br>
Is it possible to sort it with one SQL query first to show the friends then the other users.
Any help would be appreciated.
Thank you.
I tried this and it works, but the problem is it give me double results of users:
select *
from `likes`
left join `users` on `users.id` = `likes.user_id`
left join `friends` on `friends.user_id` = `likes.user_id`
or `friends.friend_id` = `likes.user_id`
where `likes.id` = 1
order by `friends.user_id` = 5
or `friends.friend_id` = 5
You need to work with a UNION here to merge the liked users with the befriended users. Upon doing this, you can create an artificial column friend, that you fill with 1 in the friend query and 0 in the like query. Later on you can order by that column.
SELECT
friends.user_id,
1 as friend,
users.*
FROM
friends
JOIN users ON users.id = friends.friend_user_id
UNION SELECT
likes.user_id,
0 as friend,
users_liked.*
FROM
likes
JOIN users as users_liked ON likes.like_user_id = users_liked.id
WHERE
user_id = '$userId'
ORDER BY friend DESC, id ASC
This will return a list of all friends, followed by a list of all liked users.

Count occurrences of distinct values with multiple tables

I have 3 tables in a database that have similar values and the same table structure. I am trying to get the number of occurrences of each value by unique user.
DB Structure
View on SQLFiddle
TABLE_1
user | value | id
TABLE_2
user | value | id
TABLE_3
user | value | id
I can run the following MySQL command to retrieve the desired results on 1 table at a time.
SELECT value,COUNT(*) as count FROM TABLE_1 GROUP BY value ORDER BY count DESC;
I need to run this command across the three tables at once in order to retrieve the unique occurrences of "value" among a list of "users" that contains numerous duplicates.
Given your comments, since you want to remove duplicates, use UNION to combine the data from the tables together:
SELECT value, COUNT(*) as count
FROM (
SELECT user, value, id
FROM TABLE_1
UNION
SELECT user, value, id
FROM TABLE_2
UNION
SELECT user, value, id
FROM TABLE_3 ) t
GROUP BY value
ORDER BY count DESC;
Updated Fiddle
You need to use UNION -
SELECT value, COUNT(*) as count
FROM (
SELECT user, value, id
FROM TABLE_1
UNION
SELECT user, value, id
FROM TABLE_2
UNION
SELECT user, value, id
FROM TABLE_3 ) tables
GROUP BY value
ORDER BY count DESC;
Output -
+-------+-----+
|car |8 |
|boat |4 |
|truck |3 |
|house |2 |
|skates |1 |
|bike |1 |
+-------+-----+
to go along with the comments this is what I would recommend you do.
setup:
CREATE TABLE members (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
username varchar(255),
);
INSERT INTO members (username)
SELECT DISTINCT user FROM table1
UNION SELECT DISTINCT user FROM table2
UNION SELECT DISTINCT user FROM table3;
altering:
ALTER table1
ADD COLUMN user_id INT(10)
ADD INDEX `user_id` (`user_id`);
ALTER table2
ADD COLUMN user_id INT(10)
ADD INDEX `user_id` (`user_id`);
ALTER table3
ADD COLUMN user_id INT(10)
ADD INDEX `user_id` (`user_id`);
updating:
UPDATE table1 t,
JOIN members m ON m.username = t.username
SET t.user_id = m.id;
UPDATE table2 t,
JOIN members m ON m.username = t.username
SET t.user_id = m.id;
UPDATE table3 t,
JOIN members m ON m.username = t.username
SET t.user_id = m.id;
removing non normalized data
ALTER table1
DROP user;
ALTER table2
DROP user;
ALTER table3
DROP user;
now you can also set up foreign key contstraints on the user_id and id columns if you would like.
but to query a total count you can just join the tables.. make sure you add an index on each of the id fields so it will join properly.
SELECT your_stuff
FROM members m
LEFT JOIN table1 t1 ON t1.user_id = m.id
LEFT JOIN table2 t2 ON t2.user_id = m.id
LEFT JOIN table3 t3 ON t3.user_id = m.id

Get only last chat message of whole friend list of a user from database

I need a query in sql which can get me the details of the last message of all the friends of the user .The fields in my sql database are :
message_id (primary key)
sender (username of the sender)
message_content (text of the message)
user_id (user id of the app user)
friend_id (user id of the app user's friends)
message_time (time of the message receive on server)
receiver (user id of the receiver)
Edit : So far I think my closest try was
Select * from user_chat_messages where message_id on (Select distinct message_id from user_chat_messages order by message_time limit 1,0);
Rest all other queries that I tried were a total failure :(
This is a very common mysql problem where you need to join a table on itself to get a result set with the min / max of each unique user.
Try something like this:
SELECT t1.* FROM table t1
JOIN (
SELECT MAX(message_time) AS 'time', friend_id, user_id
FROM table GROUP BY friend_id, user_id
) t2 ON (t1.message_time = t2.time AND t1.friend_id = t2.friend_id AND t1.user_id = t2.user_id)
Essentially your subquery finds the latest time grouped by friend_id and then joins it back to the main table so that it only pulls the record with the latest time from the first table. From there you can add a WHERE statement to only show the latest messages from a specific user - adding the condition in the subquery will actually improve the performance
SELECT t1.* FROM table t1
JOIN (
SELECT MAX(message_time) AS 'time', friend_id, user_id
FROM table
WHERE user_id=? GROUP BY friend_id
) t2 ON (t1.message_time = t2.time AND t1.friend_id = t2.friend_id AND t1.user_id = t2.user_id)

Inner Join Query Advice

i need help on creating an inner join query.
I have 2 tables, blogs and followers.
In the blogs table i have all the blog information, and then in the followers i have two fields which are the user id and then the blog id that the user follows.
I want to create a query that will order the blogs by how many followers there are.
So this is an example of what i use to show what builds a user is following (for reference):
$query = "SELECT * FROM blogs INNER JOIN followers ON (blogs.id = followers.blogid) WHERE followers.userid='" .$usernamesesh. "'";
How can i go about creating a similiar query that will select all the blogs, but order them by highest to lowest followers.
Hope this makes sense, i cant get my head around this one for some reason!
The only other option is to add a number of followers field in the blogs table but that would involve changing my follow script etc.
Craig.
Without knowing the exact structure of you tables it's hard to tell. Assuming your followers table looks something like this
blogid | userid
-------+----------
1 | 2
-------+----------
1 | 1
-------+----------
1 | 3
-------+----------
2 | 2
-------+---------
SELECT blogid, COUNT(userid) AS UserCount FROM followers
GROUP BY blogid ORDER BY UserCount DESC;
You can then to join the blogs table to get what ever columns you need from that table.
SELECT blogs.*, IFNULL(f.UserCount,0) AS UserCount
FROM blogs
LEFT JOIN (
SELECT blogid, COUNT(userid) AS UserCount FROM followers
GROUP BY blogid
) f
ON f.blogid = blogs.id
ORDER BY UserCount DESC
I would recommend tweaking Mihai's suggestion a little bit, so add this string to the end of your query: GROUP BY blogs.id ORDER BY COUNT(userid) DESC
$query = "SELECT blogs.id, count(*) AS total FROM blogs INNER JOIN followers ON (blogs.id = followers.blogid) WHERE followers.userid='" .$usernamesesh. "'" GROUP BY blogs.id ORDER BY total;
Hope this helps
You could join against a subquery:
SELECT blogs.*, s.cnt
FROM blogs
LEFT JOIN (SELECT blogid, count(*) as cnt
FROM followers
GROUP BY blogid) s
ON s.blogid = blogs.id
ORDER BY s.cnt
Edit
With
CREATE TABLE blogs (id);
create TABLE followers(blogid);
INSERT into blogs values (1),(2),(3);
INSERT into followers values (1),(1),(3);
You get:
id cnt
---------- ----------
2
3 1
1 2

MySQL Query Multiple Joins with Incorrect Results

I have 3 tables structured like so:
activity table:
activity_id, user_id, type, date
reviews table:
review_id, activity_id, fishery_id, review, date
updates table:
update_id, activity_id, update, date
I want to call the all the reviews and updates which are linked to a user by the activity table however this query returns incorrect results, any ideas?
query('
SELECT *
FROM activity as activity
LEFT JOIN reviews AS reviews
ON activity.activity_id = reviews.activity_id
LEFT JOIN updates AS updates
ON activity.activity_id = updates.activity_id
WHERE user_id = 1
');
Thanks, Matt
You're trying to select two different sets of data, the only way I can thing of doing this in one SQL statement, is to use a union, and create some extra columns to tell the difference.
SELECT 'review' as type,r.review_id as id,r.fishery_id as fid,
r.review as review,null as update,r.date as date
FROM reviews r,activity a
WHERE r.activity_id=a.activity_id AND a.user_id=#user_id
UNION
SELECT 'updates' as type,u.update_id as id,null as fid,
null as review,u.update update,u.date as date
FROM updates u,activity a
WHERE u.activity_id=a.activity_id AND a.user_id=#user_id
You probably don't want reviews and updates in the same rows, which appears to be what you are trying to do. So, you need two queries, not one, which would be:
SELECT r.review_id, r.fishery_id, r.review, r.date
FROM reviews r
WHERE EXISTS (SELECT 1 FROM activity a
WHERE a.user_id = #user_id
AND a.activity_id = r.activity_id)
SELECT u.update_id, u.update, u.date
FROM update u
WHERE EXISTS (SELECT 1 FROM activity a
WHERE a.user_id = #user_id
AND a.activity_id = u.activity_id)
Just for reference the working query:
SELECT type, review_id, activity.activity_id, review, activity.date, fishery_id
FROM activity as activity
JOIN reviews AS reviews
ON activity.activity_id = reviews.activity_id
UNION
SELECT type, activity_id, activity.activity_id, activity, activity.date, NULL
FROM activity as activity
JOIN activity AS activity
ON activity.activity_id = activity.activity_id
WHERE activity.user_id = 1
ORDER BY date DESC

Categories