Hey again, im still getting a hang of Queries and stuff so please excuse all the frequent sql questions 8)
Anyways im trying to select rows after a certain value.
Dont understand? Ok this is how it actually looks.
Table: messages
+------------+-----------+---------+-------+---------------------------------------+----------------+------------------+
| message_id | thread_id | user_id | to_id | body | message_status | uid_sent_deleted |
+------------+-----------+---------+-------+---------------------------------------+----------------+------------------+
| 1 | 1 | 1 | 7 | How are you bro? | read | 1 |
| 2 | 1 | 7 | 1 | IM good what about you kenny? | read | 0 |
| 3 | 1 | 1 | 7 | Same just chilling how is your sister | read | 1 |
| 4 | 1 | 7 | 1 | Shes coool u know just doin great | read | 0 |
| 7 | 1 | 1 | 7 | Thats nice | read | 1 |
| 8 | 1 | 7 | 1 | Yupp | read | 0 |
| 9 | 1 | 1 | 7 | hhahaha | read | 1 |
| 10 | 1 | 7 | 1 | anyways.... | unread | 0 |
+------------+-----------+---------+-------+---------------------------------------+----------------+------------------+
Where the message id is 9, is has the value of '1' in the column uid_sent_deleted.
Im trying to select rows after the last row that has a value of '1' in the column uid_sent_deleted.
here is the sql that im currently working with. Thanks for the help!!
SELECT message_id, thread_id, messages.user_id, to_id, body, message_status, uid_sent_deleted
FROM messages
INNER JOIN messages_thread ON messages_thread.id = messages.thread_id
WHERE thread_id =1
GROUP BY messages.message_id
ORDER BY message_id ASC
... WHERE thread_id = 1 AND id >
(SELECT MAX(id) FROM messages WHERE uid_sent_deleted = 1)
SELECT message_id, thread_id, messages.user_id, to_id, body, message_status, uid_sent_deleted
FROM
(SELECT thread_id t_id, MAX(message_id) m_id
FROM messages
WHERE thread_id =1 and uid_sent_deleted = 1
GROUP BY thread_id) n
inner join messages on messages.message_id > n.m_id and messages.thread_id = n.t_id
INNER JOIN messages_thread ON messages_thread.id = messages.thread_id
ORDER BY message_id ASC
LIMIT 1
A subquery might work, you select the MAX(message_id) WHERE uid_sent_deleted=1, then do you join ... little hazy on the syntax.
Related
i'm trying to select some data in the following way:
field:
+----------+------------+-----------+
| id | room_id | server_id |
+----------+------------+-----------+
| 1 | 34 | 0 |
| 2 | 34 | 0 |
| 3 | 35 | 1 |
+----------+------------+-----------+
user_position:
+----------+------------+-----------+
| user_id | server_id | position |
+----------+------------+-----------+
| 11 | 0 | 2 |
| 17 | 1 | 25 |
| 19 | 0 | 28 |
+----------+------------+-----------+
room:
+----------+------------+-----------+
| id | server_id | background|
+----------+------------+-----------+
| 34 | 0 | #d91a1a |
| 35 | 1 | #f81b2a |
| 36 | 0 | #191b4a |
+----------+------------+-----------+
RESULT:
(I hope I didn't mess it up)
+----------+------------+-----------+------------+------------+
| id | server_id | background| room_id | user_id |
+----------+------------+-----------+------------+------------+
| 1 | 0 | #d91a1a | 34 | null |
| 2 | 0 | #d91a1a | 34 | 11 |
| 3 | 1 | #f81b2a | 35 | null |
| 25 | 1 | null | null | 17 |
| 28 | 0 | null | null | 19 |
+----------+------------+-----------+------------+------------+
Unfortunately i couldn't write the right query to achieve this result. The best I could get was that the field.id, user_position.position and field.room_id, user_position.room_id columns were separated. I have no idea how to merge them together.
Can somebody help me?
UPDATE
OK, so after some trying I got this:
SELECT field.id, field.server_id, field.room_id, null AS user_id, room.background
FROM field
LEFT JOIN room ON room.id = field.room_id
WHERE field.server_id = 0
UNION
SELECT user_position.position, user_position.server_id, null, user_position.user_id, room.background
FROM user_position
LEFT JOIN room ON room.id = (SELECT field.room_id FROM field WHERE field.id = user_position.position)
WHERE user_position.server_id = 0
Now it is working I just want to ask if there isn't a better way to achieve the same result. Or do you think this query is good enough?
With the given set of data, you may try below -
SELECT COALESCE(F.id, UP2.position) id
,COALESCE(F.server_id, UP2.server_id) server_id
,UP2.background
,F.room_id
,UP2.user_id
FROM field F
LEFT OUTER JOIN (SELECT UP.server_id, R.background, UP.position, UP.user_id
FROM (SELECT server_id, position, user_id, ROW_NUMBER()OVER(PARTITION BY server_id ORDER BY user_id) rn
FROM user_position) UP
JOIN (SELECT server_id, background, ROW_NUMBER()OVER(PARTITION BY server_id ORDER BY id) rn
FROM room) R ON UP.rn = R.rn
AND UP.server_id = R.server_id) UP2 ON F.id = UP2.position
UNION
SELECT COALESCE(F.id, UP3.position) id
,COALESCE(F.server_id, UP3.server_id) server_id
,UP3.background
,F.room_id
,UP3.user_id
FROM field F
RIGHT OUTER JOIN (SELECT UP.server_id, R.background, UP.position, UP.user_id
FROM (SELECT server_id, position, user_id, ROW_NUMBER()OVER(PARTITION BY server_id ORDER BY user_id) rn
FROM user_position) UP
JOIN (SELECT server_id, background, ROW_NUMBER()OVER(PARTITION BY server_id ORDER BY id) rn
FROM room) R ON UP.rn = R.rn
AND UP.server_id = R.server_id) UP3 ON F.id = UP3.position
ORDER BY id
Here is the demo.
I have a table like this:
// notifications
+----+--------+-----------+---------+--------------------+
| id | money | post_id | user_id | belongs_to_user_id |
+----+--------+-----------+---------+--------------------+
| 1 | 5 | 1 | 123 | 101 |
| 2 | 10 | 2 | 123 | 101 |
| 3 | -2 | 4 | 456 | 101 |
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 7 | 5 | 4 | 789 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
And here is my query:
SELECT * FROM notifications
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY id DESC
LIMIT 3
The current output should be something like this:
+----+--------+-----------+---------+--------------------+
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
The seventh row is grouped and we cannot see it in the result. That's exactly the problem. Here is the expected result:
+----+--------+-----------+---------+--------------------+
| 5 | -2 | 2 | 456 | 101 |
| 6 | -2 | 3 | 123 | 101 |
| 7 | 5 | 4 | 789 | 101 |
| 8 | 10 | 4 | 789 | 101 |
+----+--------+-----------+---------+--------------------+
If I remove GROUP BY, then the fifth will be omitted. So here is the logic:
I want to the last three rows (regardless grouping). In other word, Emm ... it's hard to say, I want to select grouped rows (but not counting in LIMIT).
Any idea how can I do that?
It shows comma separated id by groups
SELECT
GROUP_CONCAT(id),
post_id
FROM notifications
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY id DESC
LIMIT 3
Please try this query. It will get the last three "groups", and then extract all the rows of those groups (using a join):
SELECT t.*
FROM notifications t
INNER JOIN (SELECT s.post_id, s.user_id
FROM notifications s
WHERE belongs_to_user_id = 101
GROUP BY post_id, user_id
ORDER BY post_id DESC, user_id DESC
LIMIT 3) u
ON u.post_id = t.post_id
AND u.user_id = t.user_id
WHERE t.belongs_to_user_id = 101
ORDER BY t.id
Update: same query using DISTINCT in the subquery:
SELECT t.*
FROM notifications t
INNER JOIN (SELECT DISTINCT s.post_id, s.user_id
FROM notifications s
WHERE belongs_to_user_id = 101
ORDER BY post_id DESC, user_id DESC
LIMIT 3) u
ON u.post_id = t.post_id
AND u.user_id = t.user_id
WHERE t.belongs_to_user_id = 101
ORDER BY t.id
Please try this
SELECT * FROM notifications WHERE belongs_to_user_id = 101 GROUP BY id, money ORDER BY id DESC
So, you want correlation subquery if i am not wrong
select * from table t
where belongs_to_user_id = 101 and
user_id = (select max(user_id) from table where post_id = t.post_id)
Additionally, you could add limit clause to limit the records that you want.
I have 3 tables:
Users
| id | name |
|----|-------|
| 1 | One |
| 2 | Two |
| 3 | Three |
Likes
| id | user_id | like |
|----|---------|-------|
| 1 | 1 | 3 |
| 2 | 1 | 5 |
| 3 | 2 | 1 |
| 4 | 3 | 2 |
Transations
| id | user_id | transaction |
|----|---------|-------------|
| 1 | 1 | -1 |
| 2 | 2 | 5 |
| 3 | 2 | -1 |
| 4 | 3 | 10 |
I need get sum of likes.like and transations.transation for each user and then sort it by its result.
I was able to do it for users and likes:
select users.*, sum(likes.like) as points
from `users`
inner join `likes` on `likes`.`user_id` = `users`.`id`
group by `users`.`id`
order by points desc
But then I add transactions table like this:
select users.*, (sum(likes.like)+sum(transactions.`transaction`)) as points
from `users`
inner join `likes` on `likes`.`user_id` = `users`.`id`
inner join `transactions` on `transactions`.`user_id` = `users`.`id`
group by `users`.`id`
order by points desc
It is show wrong results.
I expecting to see:
| id | name | points |
|----|-------|--------|
| 3 | Three | 12 |
| 1 | One | 7 |
| 2 | Two | 5 |
But get this instead:
| id | name | points |
|----|-------|--------|
| 3 | Three | 12 |
| 1 | One | 6 |
| 2 | Two | 5 |
So, how sort users by sum likes.like and transations.transation?
Thank you!
Since there's not a 1-to-1 relationships between transactions and likes, I think you need to use subqueries:
select users.*,
(select sum(points) from likes where user_id = users.id) as points,
(select sum(transaction) from transactions where user_id = users.id) as transactions
from users
order by points desc
Updated after more explanation of requirements:
select users.*,
(select sum(points) from likes where user_id = users.id) +
(select sum(transaction) from transactions where user_id = users.id) as points
from users
order by points desc
Here is how my database looks like:
table: conversations
+----+--------+--------+
| id | user_1 | user_2 |
+----+--------+--------+
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 1 | 3 |
+----+--------+--------+
table: messages
+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 1 | 1 | hej |
| 2 | 1 | test |
| 3 | 2 | doh |
| 4 | 2 | hi |
| 5 | 3 | :) |
| 6 | 3 | :D |
+----+--------------+------+
Then when I run the followin query:
SELECT
*
FROM `messages`
INNER JOIN `conversations`
ON `conversations`.`id` = `messages`.`convesations`
GROUP BY `conversations`.`id`
ORDER BY `messages`.`id` DESC
Then I get those out from messages:
+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 1 | 1 | hej |
| 3 | 2 | doh |
| 5 | 3 | :) |
+----+--------------+------+
But, is it somehow possible to do so that I will get the messages with the highest messages.id from that group, instead of the lowest?
EDIT: Here is the output I want from messages:
+----+--------------+------+
| id | conversation | text |
+----+--------------+------+
| 2 | 1 | test |
| 4 | 2 | hi |
| 6 | 3 | :D |
+----+--------------+------+
As those are the messages in same conversation with the highest id.
SELECT *
FROM conversations c
JOIN messages m
ON m.id =
(
SELECT id
FROM messages mi
WHERE mi.conversation = c.id
ORDER BY
mi.conversation DESC, mi.id DESC
LIMIT 1
)
Create an index on messages (conversation, id) for this to work fast.
You simply need to use nested query like this:
SELECT * FROM Messages
WHERE ID IN(
SELECT Max(m.ID) FROM Messages m
INNER JOIN conversations c
ON c.id = m.conversation
GROUP BY m.conversation
);
Output:
| ID | CONVERSATION | TEXT |
----------------------------
| 2 | 1 | test |
| 4 | 2 | hi |
| 6 | 3 | :D |
If you want data from both tables try this:
SELECT * FROM Messages m
JOIN conversations c
ON c.id = m.conversation
WHERE m.ID IN (
SELECT MAX(ID) FROM Messages
GROUP BY conversation
)
GROUP BY m.conversation;
Output:
| ID | CONVERSATION | TEXT | USER_1 | USER_2 |
----------------------------------------------
| 2 | 1 | test | 1 | 2 |
| 4 | 2 | hi | 2 | 3 |
| 6 | 3 | :D | 1 | 3 |
See this SQLFiddle
You are making your Join on the wrong column. 'Id' in Conversation cannot be equal to 'Id' in messages.
I thin, 'Conversation' in table messsages is 'id_conversation' right?
So, if I understood well :
SELECT *
FROM messages
INNER JOIN conversations
ON conversations.id = messages.conversation
GROUP BY conversations.id
ORDER BY messages.id DESC
I think you just have an incorrect table join:
SELECT *
FROM `messages`
INNER JOIN `conversations`
ON `conversations`.`id` = `messages`.`conversation`
GROUP BY `conversations`.`id`
ORDER BY `messages`.`id` DESC
Edit
You can try this:
SELECT *
FROM `messages`
WHERE `messages`.`id` IN (
SELECT MAX(id)
FROM messages
GROUP BY conversation
)
A couple of different approaches:
This approach relies on known but undocumented behaviour within MySQL, where the unaggregated, ungrouped values returned in a grouped query are the first in the sort order - it's fast, but should not be viewed as reliable:
SELECT * FROM
(SELECT * FROM messages
ORDER BY conversation, id desc) a
GROUP BY conversation
Alternatively, an approach that should always be reliable:
SELECT m.*, c.user_1, c.user_2 FROM messages m
JOIN (select conversation, max(id) max_id from messages group by conversation) l
ON m.id = l.max_id
JOIN conversations c
ON c.id = m.conversation
GROUP BY conversation
SQLFiddle here.
I'm stucked with a Mysql query, can you help me?
I have two tables:
user
id | name
1 | foo1
2 | foo2
3 | foo3
posts
id | id_user | created_at | kind
1 | 2 | 15-03-2011 | a
1 | 2 | 14-03-2011 | b
2 | 3 | 13-03-2011 | a
1 | 2 | 12-03-2011 | b
What I want is to retrieve the latest post of each user (the kind doesn't matter) ordered by de creation date.
How can I do that?
Thank you guys
One possible query is:
SELECT
u.id,
(SELECT MAX(p.created_at) FROM posts AS p WHERE u.id = p.id_user) AS latest
FROM
user AS u;
although the dependent subquery may not be the best solution to this. Example output:
users:
+------+------+
| id | name |
+------+------+
| 0 | test |
| 1 | one |
+------+------+
posts:
+------+---------+------------+------+
| id | id_user | created_at | kind |
+------+---------+------------+------+
| 0 | 0 | 2011-02-05 | a |
| 1 | 1 | 2011-02-06 | b |
| 2 | 0 | 2011-02-03 | a |
| 3 | 1 | 2011-02-02 | b |
+------+---------+------------+------+
output:
+------+------------+
| id | latest |
+------+------------+
| 0 | 2011-02-05 |
| 1 | 2011-02-06 |
+------+------------+
You can also add an ORDER BY latest DESC to the end of the query if you wish to get an ordered list of the latest posts across all user IDs.
Using a GROUP BY on id_user and the max post date ?
Something like that :
SELECT u.name, p.id_user, MAX( p.created_at )
FROM posts AS p
LEFT JOIN user AS u ON u.id
WHERE p.id_user = u.id
GROUP BY id_user