I Have table like this:
id user_id date
1 10 2018-12-13
3 11 2018-11-29
4 12 2018-12-05
My Query looks like this:
SELECT * FROM table WHERE IN(10,11,12) AND date > 2018-11-15
Now I get all records fromt table > 2018-11-15 but I need to get first user records.
I get now:
id user_id date
1 10 2018-12-13
2 10 2018-12-01
3 11 2018-11-29
4 12 2018-12-05
5 12 2018-12-06
I need like this:
id user_id date
1 10 2018-12-13
3 11 2018-11-29
4 12 2018-12-05
One approach is to join your table to a subquery which finds the latest records for each user_id:
SELECT
t1.id,
t1.user_id,
t1.date
FROM yourTable t1
INNER JOIN
(
SELECT user_id, MAX(date) AS max_date
FROM yourTable
WHERE user_id IN (10, 11, 12)
GROUP BY user_id
) t2
ON t1.user_id = t2.user_id AND t1.date = t2.max_date
WHERE
t1.user_id IN (10, 11, 12);
To get the results in your question, you need to use grouping and find the minimum id:
SELECT t1.id, t1.user_id, t1.date
FROM table t1
INNER JOIN (SELECT MIN(id) AS min_id
FROM table
WHERE user_id IN(10, 11, 12)
AND date > 2018-11-15
GROUP BY user_id
) t2 ON t1.id = t2.id
WHERE t1.user_id IN (10, 11, 12)
AND date > 2018-11-15;
Maybe a NOT EXISTS could be used for this.
SELECT *
FROM yourtable t1
WHERE user_id IN (10, 11, 12)
AND `date` > '2018-11-15'
AND NOT EXISTS
(
SELECT 1
FROM yourtable t2
WHERE t2.user_id = t1.user_id
AND t2.id < t1.id
AND t2.`date` > '2018-11-15'
);
Test on SQL Fiddle here
Related
Hypothetical data -
tbl1 -
id
date
value1
101
2021-01-01
200
101
2021-01-03
400
tbl2 -
id
date
value2
101
2021-01-01
600
101
2021-01-02
900
My expected result is -
id
date
value1
value2
101
2021-01-01
200
600
101
2021-01-02
NaN
900
101
2021-01-03
400
NaN
select * from (select * from tbl1 where id in
(another query)) t1
left join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
union all
select * from (select * from tbl1 where id in
(another query)) t1
right join tbl2 as t2 on t1.id = t2.id and t1.date = t2.date
where t1.id is null and t1.date is null
I am unable to figure out where am I going wrong.
I think you might be overcomplicating your union query:
SELECT t1.id, t1.date, t1.value1, t2.value2
FROM tbl1 t1
LEFT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
UNION ALL
SELECT t2.id, t2.date, t1.value1, t2.value2
FROM tbl1 t1
RIGHT JOIN tbl2 t2 ON t1.id = t2.id AND t1.date = t2.date
WHERE t1.id IS NULL
ORDER BY id, date;
Demo
Collect all present (id, `date`) pairs then join source data to it:
SELECT id, `date`, tbl1.value1, tbl2.value2
FROM ( SELECT id, `date` FROM tbl1
UNION
SELECT id, `date` FROM tbl2 ) combined
LEFT JOIN tbl1 USING (id, `date`)
LEFT JOIN tbl2 USING (id, `date`);
fiddle
The solution assumes that (id, `date`) is unique over each separate source table. If not then some aggregation must be used (SUM or MAX, depends on the logic).
I like to add event duration to a previous record every time a new record gets added.
This is what I have
ID EventType EventTime EventDuration
-------------------------------------
1 TypeA 10:20 NULL
2 TypeB 09:30 NULL
3 TypeC 08:00 NULL
This is what I want to achieve:
ID EventType EventTime EventDuration
-------------------------------------
1 TypeA 10:20 00:50
2 TypeB 09:30 01:30
3 TypeC 08:00 ...
4 ... ...
When a new records gets added (with ID, EventType and EventTime), the duration of the previous record (timediff between TypeB and Type A) should be added to the previous record in column EventDuration.
What I have so far is:
SELECT
id, EventTime,
timestampdiff(minute,
(SELECT EventTime
FROM TableName t2
WHERE t2.id < t1.id ORDER BY t2.id DESC LIMIT 1),EventTime)
AS EventDuration
FROM records t1
WHERE id = ....<this is where I get stuck, this should be a query that identifies the ID of latest EventTime record>
Any suggestions?
(I am running MySQL 5.6.39)
If you are running MySQL 8.0, you can use window functions for this:
update mytable t
inner join (
select id, timediff(eventTime, lag(eventTime) over(order by eventTime)) event_duration
from mytable t
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration
If you want to update only the last but 1 record, you can order by and limit in the subquery (or in the outer query):
update mytable t
inner join (
select id, timediff(eventTime, lag(eventTime) over(order by eventTime)) event_duration
from mytable t
order by id desc
limit 1, 1
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration
In earlier versions, one option is to emulate lag() with a window function:
update mytable t
inner join (
select
id,
timediff(
(select min(eventTime) from mytable t1 where t1.eventTime > t.eventTime),
eventTime
) event_duration
from mytable t
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration
I have multiple tables to merge and these tables may have different ID values.
For example:
Table 1:
ID Year Month Size1
A 2015 4 10
B 2015 5 20
Table 2:
ID Year Month Size2
A 2015 4 20
C 2015 5 40
Table 3:
ID Year Month Size3
D 2015 6 50
E 2015 7 50
I want the merged table to look like this:
ID Year Month Size1 Size2 Size3
A 2015 4 10 20 NULL
B 2015 5 20 NULL NULL
C 2015 5 NULL 40 NULL
D 2015 6 NULL NULL 50
E 2015 7 NULL NULL 50
I want the output ID column to include all distinct IDs from all the tables.
My guess is that this can be somehow achieved by using Full Outer Join On ID, but I wasn't quite able to produce the desired output format.
Here's another possible query that would give the result you show:
SELECT t.id, t.year, t.month,
SUM(size1) AS size1, SUM(size2) AS size2, SUM(size3) AS size3
FROM (
SELECT id, year, month, size1, NULL AS size2, NULL AS size3 FROM t1
UNION ALL
SELECT id, year, month, NULL, size2, NULL FROM t2
UNION ALL
SELECT id, year, month, NULL, NULL, size3 FROM t3
) AS t
GROUP BY t.id, t.year, t.month;
select t1.id, t1.year, t1.month, t1.size1, t2.size2, t3.size3
from table1 as t1
left outer join table2 as t2 on t1.id = t2.id and t1.year = t2.year and t1.month = t2.month
left outer join table3 as t3 on t1.id = t3.id and t1.year = t3.year and t1.month = t3.month
union
select t3.id, t3.year, t3.month, t1.size1, t2.size2, t3.size3
from table3 as t3
left outer join table1 as t1 on t3.id = t1.id and t3.year = t1.year and t3.month = t1.month
left outer join table2 as t2 on t3.id = t2.id and t3.year = t2.year and t3.month = t2.month
I have this table e.g.:
Id StatusDate Status
1 20-08-2014
1 15-08-2014
1 09-08-2014 P
2 17-08-2014
1 10-08-2014
2 12-08-2014
2 06-07-2014 P
1 30-07-2014
2 02-07-2014
2 01-07-2014 P
...... and so on
I want to select count by ID where status is blank until I hit the first 'P' in ascending order of date group by ID. So my results will be like this.
ID Count
1 3
2 2
Try it out. Not tested
SELECT t1.ID, count(*) FROM table t1
WHERE t1.StatusDate >= (SELECT MAX(t2.StatusDate) FROM table t2
WHERE t1.ID = t2.ID AND t2.Status = 'P')
GROUP BY t1.ID
Assuming your table name is StatusTable This will work:
SELECT
ID,
COUNT(*) AS `Count`
FROM StatusTable AS st
WHERE
st.Status = ''
AND st.StatusDate > (
SELECT st2.StatusDate
FROM `StatusTable` AS st2
WHERE st.ID = st2.ID
AND st2.Status = 'P'
ORDER BY st2.StatusDate DESC
LIMIT 1
)
GROUP BY st.ID
ORDER BY st.ID
One option is to use a JOIN and COUNT rows which have a lower statusdate value, like this:
SELECT t1.id, SUM(CASE WHEN t1.statusdate > t2.statusdate THEN 1 ELSE 0 END) AS mycount
FROM t t1 JOIN (
SELECT id, MIN(statusdate) statusdate
FROM t
WHERE status = 'P'
GROUP BY id
) t2
ON t1.id = t2.id
GROUP BY t1.id
Working Demo: http://sqlfiddle.com/#!2/d9d91/2
I have a MySQL table of the following form
account_id | call_date
1 2013-06-07
1 2013-06-09
1 2013-06-21
2 2012-05-01
2 2012-05-02
2 2012-05-06
I want to write a MySQL query that will get the maximum difference (in days) between successive dates in call_date for each account_id. So for the above example, the result of this query would be
account_id | max_diff
1 12
2 4
I'm not sure how to do this. Is this even possible to do in a MySQL query?
I can do datediff(max(call_date),min(call_date)) but this would ignore dates in between the first and last call dates. I need some way of getting the datediff() between each successive call_date for each account_id, then finding the maximum of those.
I'm sure fp's answer will be faster, but just for fun...
SELECT account_id
, MAX(diff) max_diff
FROM
( SELECT x.account_id
, DATEDIFF(MIN(y.call_date),x.call_date) diff
FROM my_table x
JOIN my_table y
ON y.account_id = x.account_id
AND y.call_date > x.call_date
GROUP
BY x.account_id
, x.call_date
) z
GROUP
BY account_id;
CREATE TABLE t
(`account_id` int, `call_date` date)
;
INSERT INTO t
(`account_id`, `call_date`)
VALUES
(1, '2013-06-07'),
(1, '2013-06-09'),
(1, '2013-06-21'),
(2, '2012-05-01'),
(2, '2012-05-02'),
(2, '2012-05-06')
;
select account_id, max(diff) from (
select
account_id,
timestampdiff(day, coalesce(#prev, call_date), call_date) diff,
#prev := call_date
from
t
, (select #prev:=null) v
order by account_id, call_date
) sq
group by account_id
| ACCOUNT_ID | MAX(DIFF) |
|------------|-----------|
| 1 | 12 |
| 2 | 4 |
see it working live in an sqlfiddle
If you have an index on account_id, call_date, then you can do this rather efficiently without variables:
select account_id, max(call_date - prev_call_date) as diff
from (select t.*,
(select t2.call_date
from table t2
where t2.account_id = t.account_id and t2.call_date < t.call_date
order by t2.call_date desc
limit 1
) as prev_call_date
from table t
) t
group by account_id;
Just for educational purposes, doing it with JOIN:
SELECT t1.account_id,
MAX(DATEDIFF(t2.call_date, t1.call_date)) AS max_diff
FROM t t1
LEFT JOIN t t2
ON t2.account_id = t1.account_id
AND t2.call_date > t1.call_date
LEFT JOIN t t3
ON t3.account_id = t1.account_id
AND t3.call_date > t1.call_date
AND t3.call_date < t2.call_date
WHERE t3.account_id IS NULL
GROUP BY t1.account_id
Since you didn't specify, this shows max_diff of NULL for accounts with only 1 call.
SELECT a1.account_id , max(a1.call_date - a2.call_date)
FROM account a2, account a1
WHERE a1.account_id = a2.account_id
AND a1.call_date > a2.call_date
AND NOT EXISTS
(SELECT 1 FROM account a3 WHERE a1.call_date > a3.call_date AND a2.call_date < a3.call_date)
GROUP BY a1.account_id
Which gives :
ACCOUNT_ID MAX(A1.CALL_DATE - A2.CALL_DATE)
1 12
2 4