Suppose I have a table messages like this:
id sender receiver content created_at
1 100 101 Hi 2015-12-01
2 100 101 Hello 2015-12-02
3 100 101 World 2015-11-02
4 103 101 Like 2015-11-05
5 103 101 Do 2015-11-04
6 105 102 ..................
With the receiver specified, I want to get the latest message and number of messages from each user, i.e. for user 101, I want to get:
2 100 101 Hello 2015-12-02 3
4 103 101 Like 2015-11-05 2
Is it possible to do that with a single statement or what's the most elegant way ?
Aggregate the information for 101 in a subquery, and then join that back to the original table:
select m.*, mm.maxca
from messages m join
(select m2.receiver, max(m2.created_at) as maxca, count(*) as cnt
from messages m2
where m2.receiver = 101
) mm
on m.receiver = mm.receiver and m.created_at = mm.created_at
where m.receiver = 101 ;
Idea here is to get latest record which can be acheived by ordering by created_at and then using group by to get the count.
SELECT a.id,a.sender,a.receiver,a.content,a.created_at,count(a.sender) from (Select * from messages order by created_at desc) a group by sender ;
SELECT x.*
, y.total
FROM my_table x
JOIN
( SELECT receiver
, sender
, MAX(created_at) max_created_at
, COUNT(*) total
FROM my_table
GROUP
BY receiver
, sender
) y
ON y.receiver = x.receiver
AND y.sender = x.sender
AND y.max_created_at = x.created_at
-- [WHERE receiver = 101]
;
+----+--------+----------+---------+------------+-------+
| id | sender | receiver | content | created_at | total |
+----+--------+----------+---------+------------+-------+
| 2 | 100 | 101 | Hello | 2015-12-02 | 3 |
| 4 | 103 | 101 | Like | 2015-11-05 | 2 |
| 6 | 105 | 102 | Re | 2015-11-04 | 1 |
+----+--------+----------+---------+------------+-------+
http://www.sqlfiddle.com/#!9/3fef7/1
Related
I would like to ask for help to display some information regarding queries made in a database. I have a table called membervalues. In this table, I have 4 fields => (id, memberid, submit_datetime, value). I want to show maximum and minimum value of each member based on record id. For example, I have following
id | memberid | submit_datetime | value
------------------------------------------------
1 | 1 | 2018-01-18 09:44:00 | 86
2 | 2 | 2018-01-18 10:32:00 | 95
3 | 3 | 2018-01-18 11:19:00 | 74
4 | 1 | 2018-01-18 17:57:00 | 84
5 | 3 | 2018-01-18 18:31:00 | 96
7 | 1 | 2018-01-19 06:31:00 | 86
8 | 2 | 2018-01-19 07:31:00 | 94
9 | 1 | 2018-01-19 08:31:00 | 87
What one query will return the following result in php loop?
memberid | min_record_value | max_record_value
------------------------------------------------
1 | 86 | 87
2 | 95 | 94
3 | 74 | 96
I can get the min and max id but through min(id) and max(id) with GROUP BY memberid, but I am not able to figure how to get record value with it as I required above. While searching I came across mysql - join first and last records by group type? and tried to opt for similar approach with
select x2.memberid, x2.value as min_record_value, y2.value as max_record_value
from (select *
from (select memberid, value
from membervalues
order by 1, 2) x1
group by 1) x2
join (select *
from (select memberid, value
from membervalues
order by 1, 2 desc) y1
group by 1) y2 on y2.memberid = x2.memberid
but it returns only first rows value for both as below.
memberid | min_record_value | max_record_value
------------------------------------------------
1 | 86 | 86
2 | 95 | 95
3 | 74 | 74
Any help will be greatly appreciated. Thanks
You can use the row_number() window function to assign a number, starting from 1, to each record for each memberid depending on the position of the record when ordered by submit_datetime and id (to resolve possible ties). Once in ascending order for the minimum and once in descending order for the maximum. Then you can join the derived table on common memeberid and that number and filter for that number being 1.
SELECT xmi.memberid,
xmi.value min_record_value,
xma.value max_record_value
FROM (SELECT v1.memberid,
v1.value,
row_number() OVER (PARTITION BY v1.memberid
ORDER BY v1.submit_datetime ASC,
v1.id ASC) rn
FROM membervalues v1) xmi
INNER JOIN (SELECT v2.memberid,
v2.value,
row_number() OVER (PARTITION BY v2.memberid
ORDER BY v2.submit_datetime DESC,
v2.id DESC) rn
FROM membervalues v2) xma
ON xma.memberid = xmi.memberid
AND xma.rn = xmi.rn
WHERE xma.rn = 1
AND xmi.rn = 1;
I would like know how to build a query based another query result.
for example:
I have this table named groups:
group_id | user_id | is_admin
146 | 1 | 1
146 | 3 | 1
146 | 6 | 1
146 | 7 | 1
102 | 21 | 1
105 | 174 | 1
109 | 369 | 1
So, I execute this query to get all groups based on user_id
SELECT * FROM groups WHERE user_id = 6;
The result is?
group_id | user_id | is_admin
146 | 6 | 1
But, I would like to get now, all groups based on group_id. So, I would like
execute this query:
SELECT * FROM groups where group_id = 146;
So, I have this query result:
group_id | user_id | is_admin
146 | 1 | 1
146 | 3 | 1
146 | 6 | 1
146 | 7 | 1
In resume, I would like find which group or user belongs and select all rows that contain their group_id
1 - SELECT * FROM groups WHERE user_id = 6;
2 - SELECT * FROM groups WHERE groups in (146,102, ...);
NOTE: The user_id can belong to more than one group.
Thank you.
Use = and a subquery if you only expect one group per user (as in your sample data):
select g.*
from groups g
where g.group_id = (select g2.group_id from groups g2 where g2.user_id = 6);
Use in if a user could be in multiple groups:
select g.*
from groups g
where g.group_id in (select g2.group_id from groups g2 where g2.user_id = 6);
Hi I have a table like so:
SN | User | is_borrowed | date
105 | 1 | 1 |2019-1-1
105 | 1 | 0 |2019-2-1
105 | 1 | 1 |2019-3-1
106 | 2 | 1 |2019-4-1
107 | 1 | 1 |2019-5-1
106 | 2 | 0 |2019-6-1
106 | 2 | 1 |2019-8-1
107 | 1 | 0 |2019-9-1
107 | 2 | 1 |2019-10-1
Wanted output is to show what is borrowed (not returned) and user=1:
SN | User | is_borrowed | date
105 | 1 | 1 |2019-3-1
Output for User=2 and borrowed (not returned):
SN | User | is_borrowed | date
106 | 2 | 1 |2019-8-1
107 | 2 | 1 |2019-10-1
In summary I want a list of devices currently borrowed that are not returned for each user. Sadly nothing comes to my mind tho :/
looking to your expected result seems you are looking for the max(date) for SN, user where is_borrowed = 1
select SN, user, is_borrowed, max(date)
from my_table
where is_borrowed = 1
group by SN, user, is_borrowed
or for the device actual borrowed
Select * from my_table m
inner join t (
select SN, is_borrowed, max(date) max_date
from my_table
where is_borrowed = 1
group by SN, is_borrowed
) t on t.SN = m.SN AND t.max_date = m.date
SELECT t.sn, t.user, t.is_borrowed, t.date
FROM TABLE_NAME t
WHERE t.is_borrowed = 1
AND t.date =
(
SELECT MAX(x.date)
FROM TABLE_NAME x
WHERE x.user = t.user
)
AND (
SELECT xx.is_borrowed
FROM TABLE_NAME xx
WHERE t.sn = xx.sn
AND t.date < xx.date
) <> 0
;
i have sample data like this
------------------------------------------
message_id | sender_id | receiver_id | message
------------------------------------------
1 | 101 | 102 | hello
2 | 102 | 101 | i am fine
3 | 103 | 101 | where are you?
4 | 101 | 103 | i am at my home
5 | 103 | 101 | ok
6 | 101 | 102 | so whats up?
7 | 102 | 104 | i am so busy
8 | 105 | 101 | hey
I would like the latest message from each dialogue in which user 101 is a participant
Expecting output
8 | 105 | 101 | hey
6 | 101 | 102 | so whats up?
5 | 101 | 103 | i am at my home
i need mysql query for this.
thanks in advance.
E.g.:
SELECT a.*
FROM my_table a
JOIN
( SELECT LEAST(sender_id,receiver_id) user1
, GREATEST(sender_id,receiver_id) user2
, MAX(message_id) message_id
FROM my_table
WHERE 101 IN (sender_id,receiver_id)
GROUP
BY user1
, user2
) b
ON b.message_id = a.message_id;
or just
SELECT a.*
FROM my_table a
JOIN
( SELECT MAX(message_id) message_id
FROM my_table
WHERE 101 IN (sender_id,receiver_id)
GROUP
BY LEAST(sender_id,receiver_id)
, GREATEST(sender_id,receiver_id)
) b
ON b.message_id = a.message_id;
This can also be written as follows. I doubt it makes much difference to performance...
SELECT a.*
FROM my_table a
JOIN
( SELECT MAX(message_id) message_id
FROM
( SELECT message_id
, receiver_id user2
FROM my_table
WHERE sender_id = 101
UNION
SELECT message_id
, sender_id
FROM my_table
WHERE receiver_id = 101
) x
GROUP
BY user2
) b
ON b.message_id = a.message_id;
Actually, in my own limited tests, the first queries complete in half the time of the last one.
If you give bit code or your file sql will be good to answering your question.
Try this:
$query = mysqli_query($connection," SELECT * FROM your table WHERE sender_id = '101' OR receive_id = '101' GROUP BY message_id ");
return $query;
I have a points table, where important columns are:
id userid orderid
1 10 150
2 10 150
3 15 151
4 12 152
5 11 152
I need to find all orderid which have multiple/various userid. The result would be:
id userid orderid
4 12 152
5 11 152
I can do it in PHP, but I hope someone have time to help me with mysql query. What I have tried so far is probably irrelevant.
Use COUNT(DISTINCT) and HAVING to find orderid with multiple various userid.
SqlFiddleDemo
SELECT t.*
FROM tab t
JOIN (SELECT orderid, COUNT(DISTINCT userid)
FROM tab
GROUP BY orderId
HAVING COUNT(DISTINCT userid) > 1) AS sub
ON t.orderid = sub.orderid
ORDER BY t.id
If you want to get just the rows that have same orderid but different userid, use this:
SELECT P1.* FROM points P1
INNER JOIN points P2
ON P1.orderid = P2.orderid and P1.id != P2.id and P1.userid != p2.userid;
Note that this first select returns what you expect in your question:
+----+--------+---------+
| id | userid | orderid |
+----+--------+---------+
| 4 | 12 | 152 |
| 5 | 11 | 152 |
+----+--------+---------+
Now, if you want to return ANY orderid that is the same, regardless of userid, use this:
SELECT P1.* FROM points P1
INNER JOIN points P2
ON P1.orderid = P2.orderid and P1.id != P2.id;
In this case, it won't exclude the result with same id, returning
+----+--------+---------+
| id | userid | orderid |
+----+--------+---------+
| 1 | 10 | 150 |
| 2 | 10 | 150 |
| 4 | 12 | 152 |
| 5 | 11 | 152 |
+----+--------+---------+