I`m new to sql.I have two joined tables, it's posts tables posts and comments, I'm using MySql.
Post :
id, UserName, Phone , product
Comments:
id , CommentText, post_id
I'm ussing join query to join them
SELECT t1.UserName , t1.Phone, t2.Comments
FROM table1 AS t1
LEFT JOIN table2 AS t2 ON (t1.id = t2.follow_id )
And now I need to display all unique users and their last comments,so they look like that
1. User1 LastComment1
2. User2 LastComment2
3. User3 LastComment3
...
I will be very grateful for the help.
i assume that column id in both tables are AUTO_INCREMENT PRIMARY KEY.
This corelated subquery wil give you the correct answer.
Query
SELECT
Post.Username
, Post.Phone
, (SELECT
Comments.CommentText
FROM
Comments
WHERE
Comments.post_id = Post.id
ORDER BY
Comments.id DESC
LIMIT 1
)
AS LastComment
FROM
Post
You might want to add a index on the Comments.post_id to improve performance off this query.
Related
I have two tables that store comments from two different users
Table1
id_table1 | comment | id_user | id_post
Table2
id_table2 | comment | id_someOtherUser | id_post
I would really like to make only one table out of this two because comments are posted on the same post, but i can't because i have two different id's for two different kind of users.
My question is how can i list all posts DESC by number of comments combined from two tables?
If i do something like
SELECT P.*, count(*) as count from Table1 AS T1
LEFT JOIN post AS P ON T1.id_post = P.id_post GROUP BY P.id_post ORDER BY count DESC
Then i have posts for table1, same can be done for table2, but how can i combine comments from both tables for the same post?
I would use UNION ALL to combine the two comment tables in a common format, then do the JOIN:
SELECT P.*, TC.count
FROM (
SELECT Ts.id_post, count(*) AS count
FROM (
SELECT id_post FROM Table1
UNION ALL
SELECT id_post FROM Table2
) AS Ts
GROUP BY Ts.id_post
) AS TC
LEFT JOIN post AS P ON TC.id_post = P.id_post
GROUP BY P.id_post
ORDER BY TC.count DESC
One way to solve this is to do separate counts on each table, then do a full outer join, and take the sum of each of the counts:
SELECT id_post, (count1 + count2) AS total_count FROM
(SELECT id_post, count(*) as count1 from Table1 AS T1
FULL OUTER JOIN
(SELECT id_post, count(*) as count2 from Table2 AS T2)
USING(id_post))
ORDER BY total_count DESC
I have the two tables grades and feedback and the following MySQL query:
SELECT id, mingrade, maxgrade, quizid
FROM feedback
WHERE quizid=6
ORDER BY id DESC LIMIT 6
How do I need to modify the query to add userid at the first table?
What are the fields of the grades and feedback tables? Use a JOIN that links the two based on a common attribute.
SELECT column_name(s)
FROM table1
INNER JOIN table2 ON table1.column_name = table2.column_name
WHERE condition;
So if your two tables are grades and feedback, and both have the field userid you could say:
SELECT id, userid, mingrade, maxgrade, quizid
FROM feedback
INNER JOIN grades ON feedback.userid = grades.userid
WHERE quizid = 6
ORDER BY id DESC LIMIT 6;
I think that should work.
I would like to select data from a table like this (the table name is conversations_users) :
I would like to be able to retrieve a conversation ID that includes only two users. As instance, if I search a conversation specific to users 1 and 3 the conversation number 6 should be the unique result, because the conversation 5 also includes user 2.
I have tried to perform a request like
SELECT * FROM conversations_users AS table1 JOIN
conversations_users AS table2 ON
table1.conversation_ID = table2.conversationID
WHERE table1.userID = 3 AND
table2.userID = 1
But it returns both conversations 5 and 6. How can I fix that ?
Thank you in advance,
Pierre
Add the ON clause:
SELECT * FROM conversations_users AS table1 JOIN
conversations_users AS table2
ON table1.conversation_ID = table2.conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Update:
To get only coversations, where only 1 and 3 are involved, you can use having clause:
SELECT table1.conversation_ID FROM conversations_users AS table1 JOIN
conversations_users AS table2
ON table1.conversation_ID = table2.conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Group by table1.conversation_ID
having Count(*) = 2
The query you need looks like:
SELECT conversation_ID, GROUP_CONCAT(DISTINCT userID ORDER BY userID) as users
FROM conversations_users
GROUP BY conversation_ID
HAVING users = '1,3'
The GROUP BY clause groups the rows having the same conversation_ID and from each group it generates a new record that contains the conversation_ID and the distinct values of userID, in ascending order, concatenated with comma (,).
The HAVING clause keeps only those records that have '1,3' in the column users computed by the GROUP BY clause.
The query produces the output you need but it is not efficient because it reads the entire table. It could be more efficient by picking first the conversations of users 1 and 3 and then applying the above only to them.
It looks like this:
SELECT conversation_ID, GROUP_CONCAT(DISTINCT userID ORDER BY userID) as users
FROM (
SELECT *
FROM conversations_users
WHERE userID in (1, 3)
) conversations
GROUP BY conversation_ID
HAVING users = '1,3'
In order to work faster than the previous query, the conversations_users must have an index on the userID column.
If you want to restrict to those conversations which involve exactly n number of users. I think below generic query should work. Replacing 'n' as per requirement.
select *
from conversations_users
where conversation_id IN (select conversation_id
from conversations_users
group by conversation_id
having count(userid) = 2)
Thanks,
Amitabh
The inner select grabs all conversationIDs with other users than 1 or 3
the outer select (with distinct) collects all conversations wich are NOT in this subset
SELECT DISTINCT conversationID
FROM conversations_users t1
WHERE conversationID NOT IN ( SELECT conversationID
FROM conversations_users
WHERE userID NOT in (1, 3)
)
You can use join with where condition in this case.
SELECT #, userid ,conversation_ID FROM user AS table1 JOIN
conversations_users AS table2
ON user_ID = conversation_ID
WHERE table1.userID = 3 AND
table2.userID = 1
Group by conversation_ID
You can apply suitable condition by where clause instead of group by
I often have a situation with two tables in MySQL where I need one record for each foreign key. For example:
table post {id, ...}
table comment {id, post_id, ...}
SELECT * FROM comment GROUP BY post_id ORDER BY id ASC
-- Oldest comment for each post
or
table client {id, ...}
table payment {id, client_id, ...}
SELECT * FROM payment GROUP BY client_id ORDER BY id DESC
-- Most recent payment from each client
These queries often fail because the "SELECT list is not in GROUP BY clause" and contains nonaggregated columns.
Failed Solutions
I can usually work around this with a min()/max() but that creates a very slow query with mis-matched results (row with min(id) isn't equal to row with min(textfield))
SELECT min(id), min(textfield), ... FROM table GROUP BY fk_id
Adding all the columns to GROUP BY results in duplicate records (from the fk_id) which defeats the purpose of GROUP BY.
SELECT id, textfield, ... FROM table GROUP BY fk_id, id, textfield
Same idea as #GurV but using a join instead of a correlated subquery. The basic idea here is that the subquery finds, for each post which has comments, the oldest post and its corresponding id in the comments table. We then join back to comments again to restrict to the records we want.
SELECT t1.*
FROM comments t1
INNER JOIN
(
SELECT post_id, MIN(id) AS min_id
FROM comments
GROUP BY post_id
) t2
ON t1.post_id = t2.post_id AND
t1.id = t2.min_id
You can use a correlated query with aggregation to find out the earliest comment for each post:
select *
from comments c1
where id = (
select min(id)
from comments c2
where c1.post_id = c2.post_id
)
Compound index - comments(id, post_id) should be helpful.
If you are querying the whole table with many rows, then it will. This query is more useful and performant if you are querying for a small subset of posts. If you are querying the whole table, then #Tim's answer is better suited I think.
How do I do something like this in MySQL?
(1274649,682844,872502,1016256)
INTERSECT
(SELECT id FROM `users` WHERE `id` IN (1274649,682844,872502,1016256))
Adapting from the comments:
These four numbers are the IDs that I have now. I want to know which of these IDs do not have an an entry in my table, and how many of them don't have an entry?
select t.id from (
select 1274649 as id union
select 682844 union
select 872502 union
select 1016256
) t
left join users u on u.id = t.id
where u.id is null
This returns those ids that haven't corresponding id in users table.
Added this is the answer to OP explanation in comment: Which entries in my list do not have an entry in my table?