mySQL - show first and last log from each day - mysql

i have a mysql table with colums: id(primary), name(varchar), TIME(timestamp)
ID , NAME , TIME
i want to get just first and last log for each day
example if i have data like this
1,name,2018-20-21 12:35:00
2,name,2018-20-21 13:38:00
3,name,2018-20-21 14:25:00
4,name,2018-20-21 15:39:00
5,name,2018-20-21 21:48:00
6,name,2018-20-22 13:25:00
7,name,2018-20-22 14:39:00
8,name,2018-20-22 19:48:00
i want to get in just this
1,name,2018-20-21 12:35:00
5,name,2018-20-21 21:48:00
6,name,2018-20-22 13:25:00
8,name,2018-20-22 19:48:00

Try this:
SELECT name, MAX(time), MIN(time) FROM Table GROUP BY DATE(time);

You could use the union for the min and the max time group by date
and join this with your table
select * from my_table
inner join (
select * from (
select min(time) my_time
from my_table
group by date(time)
union
select max(time)
from my_table
group by date(time)
) t on t.my_time = my_table.time
order by my_table.time

Hope this helps.
SELECT id, tmp.name, tmp.time FROM
(SELECT id, name, min(time) as time FROM table1 GROUP BY DATE(time)
UNION ALL
(SELECT id, name, max(time) as time FROM table1 GROUP BY DATE(time)) tmp
ORDER BY tmp.time

You can try selecting the min and max for each day, since you want the entire line, a join is needed
and to filter out the actual min and max day, a aub query is needed
SELECT id, name, time
FROM
(
SELECT t2.*, MIN(DATE(t.time)) As min0 MAX(DATE(t.time)) As max0
FROM
table t
INNER JOIN table t2 ON t.id = t2.id
GROUP BY
DATE (t.time),
min0,
max0
) a

SELECT
l.id,l.name,l.time
FROM
log l
LEFT JOIN
(SELECT
max(time) as maxTime
FROM
log
GROUP BY date(time)) l1 ON l.time = l1.maxTime
LEFT JOIN
(SELECT
min(time) as minTime
FROM
log
GROUP BY date(time)) l2 ON l.time = l2.minTime
WHERE
(maxTime IS NOT NULL
OR minTime IS NOT NUll);
SELECT * from stack.log;

Related

only max(value) from union by several columns

I want to retrieve one result for each [Group] by the highest Time.
Result of current code:
SELECT [Group], ArticleNumber, max(TimeTrue) as Time
FROM PerformanceOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
UNION
SELECT [Group], ArticleNumber, max(StopTime) as Time
FROM StoppageOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
ORDER BY Time DESC
The result should be only two records (csv):
Group,ArticleNumber,Time
70521-030,,2021-03-15 13:50:15
Pack2,183026,2021-03-15 13:47:39
Hmmm . . . you would seem to want to union all before aggregating:
SELECT [Group], ArticleNumber, max(Time) as Time
FROM ((SELECT [Group], ArticleNumber, TimeTrue as Time
FROM PerformanceOpc
WHERE [Group] IN ('Pack2', '70521-030')
) UNION ALL
(SELECT [Group], ArticleNumber, StopTime as Time
FROM StoppageOpc
WHERE [Group] IN ('Pack2', '70521-030')
)
) g
GROUP BY [Group], ArticleNumber;
This returns one row per group and article, which seems to be what your query is doing.
If you really want only one row per group, then you want ROW_NUMBER() and not aggregation:
SELECT g.*
FROM (SELECT g.*, ROW_NUMBER() OVER (PARTITION BY [Group] ORDER BY time DESC) as seqnum
FROM ((SELECT [Group], ArticleNumber, TimeTrue as Time
FROM PerformanceOpc
WHERE [Group] IN ('Pack2', '70521-030')
) UNION ALL
(SELECT [Group], ArticleNumber, StopTime as Time
FROM StoppageOpc
WHERE [Group] IN ('Pack2', '70521-030')
)
) g
) g
WHERE seqnum = 1;
Try select top 1 with order by in temporal tables and then query them with union
SELECT top 1[Group], ArticleNumber, max(TimeTrue) as Time into #tmp1
FROM PerformanceOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
order by Time desc
SELECT top 1 [Group], ArticleNumber, max(StopTime) as Time into #tmp2
FROM StoppageOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
ORDER BY Time DESC
select * from #tmp1
union
select * from #tmp2
drop table #tmp1
drop table #tmp2

Compute 2 subqueries then group by date

I have this Table
I want to run subqueries first then add them together grouped by date
Expected Result should be like this:
I am running this query
(
SELECT DATE_FORMAT(dd1.modified_datetime,'%Y-%m-%d') as date, (v1+v2) as value FROM
(SELECT modified_datetime, Sum(data->"$.amount") as v1
FROM transactions
GROUP BY modified_datetime) as dd1 ,
(SELECT modified_datetime, MAX(data->"$.amount") as v2
FROM transactions
GROUP BY modified_datetime) as dd2
GROUP BY dd1.modified_datetime, value
)
and getting this result:
Use JOIN between subqueries and every next one:
(SELECT modified_datetime, Sum(data->"$.amount") as v1
FROM transactions
GROUP BY modified_datetime) as dd1 JOIN
(SELECT modified_datetime, MAX(data->"$.amount") as v2
FROM transactions
GROUP BY modified_datetime) as dd2 ON dd1.modified_datetime=dd2.modified_datetime
If I followed you correctly, you can use union all and aggregation:
select date_format(dt, '%Y-%m-%d') dt_day, sum(amount) value
from (
select modified_datetime dt, data ->> '$.amount' amount from transactions
union all
select created_datetime, data ->> '$.amount' from transactions
) t
group by dt_day
order by dt_day

Group by date and take the last one

This is my table :
What I'm trying to do, is to take the last disponibility of a user, by caserne. Example, I should have this result :
id id_user id_caserne id_dispo created_at
31 21 12 1 2019-10-24 01:21:46
33 21 13 1 2019-10-23 20:17:21
I've tried this sql, but it does not seems to work all the times :
SELECT * FROM
( SELECT id, id_dispo, id_user, id_caserne, MAX(created_at)
FROM disponibilites GROUP BY id_user, id_caserne, id_dispo
ORDER BY created_at desc ) AS sub
GROUP BY id_user, id_caserne
What am I doing wrong ?
I would simply use filtering in the where clause using a correlated subquery:
select d.*
from disponibilites d
where d.created_at = (select max(d2.created_at)
from disponibilites d2
where d2.id_user = d.id_user
);
EDIT:
Based on your comments:
select d.*
from disponibilites d
where d.created_at = (select max(d2.created_at)
from disponibilites d2
where d2.id_user = d.id_user and
d2.id_caserne = d.id_caserne
where date(d2.created_at) = date(d.created_at)
);
You can use a correlated subquery, as demonstrated by Gordon Linoff, or a window function if your RDBMS supports it:
select * from (
select
t.*,
rank() over(partition by id_caserne, id_user order by created_at desc) rn
from disponibilites t
) x
where rn = 1
Another option is to use a correlated subquery without aggregation, only with a sort and limit:
select *
from mytable t
where created_at = (
select created_at
from mytable t1
where t1.id_user = t.id_user and t1.id_caserne = t.id_caserne
order by created_at desc
limit 1
)
With an index on (id_user, id_caserne, created_at), this should be a very efficient option.
you can join your max(created_date) to your original table
select t1.* from disponibilites t1
inner join
(select max(created_at), id_caserne, id
from disponibilites
group by id_caserne, id) t2
on t2.id = t1.id

How to select the value from recent record?

I have table
create table events (
sensor_id integer not null,
event_type integer not null,
value integer not null,
time timestamp unique not null);
insert into events
values
(2,2,5,"2014-02-13 12:42:00"),
(2,4,-42,"2014-02-13 13:19:57"),
(2,2,2,"2014-02-13 14:48:30"),
(3,2,7,"2014-02-13 12:54:39"),
(2,3,54,"2014-02-13 13:32:36");
I want for each sensor_id and event_type only the most recent value in terms of time
expected result
sensor_id, event_type value
2 2 2
2 3 54
2 4 -42
3 2 7
I have tried query
SELECT sensor_id,event_type,value, time
from events
group by sensor_id,event_type
having time = max(time)
why it doesn't success (result table do not contain sensor_id = 2 and event_type = 2)
How could I solve this using both mysql and sqllite, is there difference in term of this ?
Use aggregation to get the maximum time, and then a join to get the rest of the record that match that time:
SELECT e.sensor_id, e.event_type, e.value, e.time
from events e join
(select sensor_id, event_type, max(time) as maxt
from events e
group by sensor_id, event_type
) ee
on e.sensor_id = ee.sensor_id and e.event_type = ee.event_type;
Try with the below one also.
select sensor_id,event_type,value, time
from events
where time in (select max(time) from events group by sensor_id, event_type)
Hope this will also work fine.
In this way it works properly
-- write your code in PostgreSQL 9.4
SELECT
E1.SENSOR_ID,
COUNT(E1.EVENT_TYPE) AS "TYPES"
FROM
(
SELECT
DISTINCT
E.SENSOR_ID,
E.EVENT_TYPE
FROM
EVENTS E
) E1
GROUP BY E1.SENSOR_ID
ORDER BY E1.SENSOR_ID ASC
SELECT sensor_id, event_type, value
from (SELECT sensor_id, event_type, value, max(time)
from events group by sensor_id, event_type)
order by sensor_id, event_type;
SELECT events.sensor_id, events.event_type, events.value
FROM events
JOIN (
SELECT sensor_id, event_type, MAX(time) as max_time
FROM events
GROUP BY sensor_id, event_type
)t on events.sensor_id = t.sensor_id and events.event_type = t.event_type and events.time = t.max_time
ORDER BY events.sensor_id, events.event_type;

mysql self join

I have a table called receiving with 4 columns:
id, date, volume, volume_units
The volume units are always stored as a value of either "Lbs" or "Gals".
I am trying to write an SQL query to get the sum of the volumes in Lbs and Gals for a specific date range. Something along the lines of: (which doesn't work)
SELECT sum(p1.volume) as lbs,
p1.volume_units,
sum(p2.volume) as gals,
p2.volume_units
FROM receiving as p1, receiving as p2
where p1.volume_units = 'Lbs'
and p2.volume_units = 'Gals'
and p1.date between "2012-01-01" and "2012-03-07"
and p2.date between "2012-01-01" and "2012-03-07"
When I run these queries separately the results are way off. I know the join is wrong here, but I don't know what I am doing wrong to fix it.
SELECT SUM(volume) AS total_sum,
volume_units
FROM receiving
WHERE `date` BETWEEN '2012-01-01'
AND '2012-03-07'
GROUP BY volume_units
You can achieve this in one query by using IF(condition,then,else) within the SUM:
SELECT SUM(IF(volume_units="Lbs",volume,0)) as lbs,
SUM(IF(volume_units="Gals",volume,0)) as gals,
FROM receiving
WHERE `date` between "2012-01-01" and "2012-03-07"
This only adds volume if it is of the right unit.
This query will display the totals for each ID.
SELECT s.`id`,
CONCAT(s.TotalLbsVolume, ' ', 'lbs') as TotalLBS,
CONCAT(s.TotalGalVolume, ' ', 'gals') as TotalGAL
FROM
(
SELECT `id`, SUM(`volume`) as TotalLbsVolume
FROM Receiving a INNER JOIN
(
SELECT `id`, SUM(`volume`) as TotalGalVolume
FROM Receiving
WHERE (volume_units = 'Gals') AND
(`date` between '2012-01-01' and '2012-03-07')
GROUP BY `id`
) b ON a.`id` = b.`id`
WHERE (volume_units = 'Lbs') AND
(`date` between '2012-01-01' and '2012-03-07')
GROUP BY `id`
) s
this is a cross join with no visible condition on the join, i don't think you meant that
if you want to sum quantities you don't need to join at all, just group as zerkms did
You can simply group by date and volume_units without self-join.
SELECT date, volume_units, sum(volume) sum_vol
FROM receving
WHERE date between "2012-01-01" and "2012-03-07"
GROUP BY date, volume_units
Sample test:
select d, vol_units, sum(vol) sum_vol
from
(
select 1 id, '2012-03-07' d, 1 vol, 'lbs' vol_units
union
select 2 id, '2012-03-07' d, 2 vol, 'Gals' vol_units
union
select 3 id, '2012-03-08' d, 1 vol, 'lbs' vol_units
union
select 4 id, '2012-03-08' d, 2 vol, 'Gals' vol_units
union
select 5 id, '2012-03-07' d, 10 vol, 'lbs' vol_units
) t
group by d, vol_units