How to get difference based on date in mysql - mysql

I have like below mentioned two table:
Table1
ID Unique_Value
T-1 OI-45
T-4 OI-45
T-8 OI-45
T-7 OI-46
T-6 OI-49
Table2
ID Date Value
T-1 2018-01-01 15:13:22 10
T-4 2018-03-15 18:10:45 15
T-8 2018-05-12 05:17:43 25
T-7 2018-04-01 15:13:22 12
T-6 2018-06-01 15:13:22 18
I have joined the Table2 ID with Table1 ID and get the Unique_Value, based on the unique value and order by Date in Descending order and group by Unique_Value, I want to get the difference value of a particular ID from the previous Value.
Required Output would be:
ID Date Value Unique_Value Difference
T-1 2018-01-01 15:13:22 10 OI-45 [Null]
T-4 2018-03-15 18:10:45 15 OI-45 5
T-8 2018-05-12 05:17:43 25 OI-45 10
T-7 2018-04-01 15:13:22 12 OI-46 [Null]
T-6 2018-06-01 15:13:22 18 OI-49 [Null]
I have tried using Lead Log but it didn't worked.

You can try below using lag() function - it will work for mysql version 8.0+
DEMO
select id,Date,value,Unique_Value,case when prevval is null then null else value-prevval end as Difference
from
(
select t1.Id,t1.Unique_Value,t2.Date,t2.value,lag(t2.value,1) over(partition by t1.Unique_Value order by t2.Date) as prevval
from table1 t1 inner join table2 t2 on t1.id=t2.id
)A
For Mysql Version 5.7 you can try below -
DEMO
SET #quot=0, #latest=0, #comp=''
select id, Unique_Value,d,value,case when latest=1 then c=null else c end as difference
from
(
select id,Unique_Value,d,value,c,IF(#comp<>Unique_Value,1,0) as LATEST,#comp:=Unique_Value as company from
(
select t1.Id,t1.Unique_Value,value,t2.d,value-#quot as c,#quot:=value
from t1 inner join t2 on t1.id=t2.id
order by t1.Unique_Value,t2.d
)A order by Unique_Value,d
)B
OUTPUT:
id d value Unique_Value Difference
T-1 2018-01-01 10 OI-45
T-4 2018-03-15 15 OI-45 5
T-8 2018-05-12 25 OI-45 10
T-7 2018-04-01 12 OI-46
T-6 2018-06-01 18 OI-49

Related

Daily Sales from Total Sales

I have a database that looks like this:
ID
Sale_Date(YYYY-MM-DD)
Total_Volume
123
2022-01-01
0
123
2022-01-02
2
123
2022-01-03
5
456
2022-04-06
38
456
2022-04-07
40
456
2022-04-08
45
I want to get a daily sale column from Total Volume. which is just by subtracting the total volume on date x with total volume on date x-1 for each id.
ID
Sale_Date(YYYY-MM-DD)
Total_Volume
Daily_Sale
123
2022-01-01
0
0
123
2022-01-02
2
2
123
2022-01-03
5
3
456
2022-04-06
38
38
456
2022-04-07
40
2
456
2022-04-08
45
5
My initial attempt was using a rank function and self join but that didnt turn out correct.
with x as (
select
distinct t1.ID,
t1.Sale_Date,
t1.Total_volume,
rank() over (partition by ID order by Sale_Date) as ranker
from t t1 order by t1.Sale_Date)
select t2.ID, t2.ranker, t2.Sale_date, t1.Total_volume, t1.Total_volume - t2.Total_volume as Daily_sale
from x t1, x t2 where t1.ID = t2.ID and t2.ranker = t1.ranker-1 order by t1.ID;
You should use:
the LAG window function to retrieve last "Sale_Date" value
the COALESCE function to replace NULL with "Total Volume" for each first rows
Then subtract Total_Volume from the previous value of Total_Volume and coalesce if the value of the LAG is NULL.
SELECT *,
COALESCE(`Total_Volume`
-LAG(`Total_Volume`) OVER(PARTITION BY `ID`
ORDER BY `Sale_Date(YYYY-MM-DD)`), `Total_Volume`) AS `Daily_Sale`
FROM tab
Check the demo here.

Select Max and Min datetime for distinct user

I have a record as below
ID(int) DATA_ORA(timestamp) BADGE LETTORE
1 2017-04-01 09:30:00 1 1
2 2017-04-01 12:30:00 1 2
3 2017-04-01 13:30:00 1 1
4 2017-04-01 18:30:00 1 2
5 2017-04-01 09:30:00 2 1
6 2017-04-01 18:30:00 2 2
7 2017-04-02 09:30:00 1 1
8 2017-04-02 18:30:00 1 2
9 2017-04-03 09:30:00 3 1
10 2017-04-03 12:30:00 3 2
11 2017-04-03 13:30:00 3 1
12 2017-04-03 18:30:00 3 2
I want to get the first access time and the last daily logout time (for each day) for each individual user (badge).
How I can do this?
The record I wish to as below
ID(int) DATA_ORA(timestamp) BADGE LETTORE
1 2017-04-01 09:30:00 1 1
4 2017-04-01 18:30:00 1 2
5 2017-04-01 09:30:00 2 1
6 2017-04-01 18:30:00 2 2
7 2017-04-02 09:30:00 1 1
8 2017-04-02 18:30:00 1 2
9 2017-04-03 09:30:00 3 1
12 2017-04-03 18:30:00 3 2
Is it possible to do that? Thanks.
NOTE: ID are auto-incremented and LETTORE 1 is entry and LETTORE 2 is exit.
You can do it grouping by date, badge and lettore like:
SELECT date(DATA_ORA),badge,lettore, case when lettore=1 then min(time(data_ora))
when lettore=2 then max(time(data_ora))
else 0
end
FROM table1
group by date(DATA_ORA),badge,lettore
try below using correlated subquery and union all
select * from tablename a
where DATA_ORA in (select min(DATA_ORA) from tablename b where a.badge=b.badge)
union
select * from tablename a
where DATA_ORA in (select max(DATA_ORA) from tablename b where a.badge=b.badge)
I like #fa06 answer, but he misses, that you want the data daily.
so try this:
select * from t1 a
where DATA_ORA in (select min(DATA_ORA) from t1 b where a.badge=b.badge GROUP BY DATE_FORMAT(DATA_ORA, '%Y%m%d'))
union
select * from t1 a
where DATA_ORA in (select max(DATA_ORA) from t1 b where a.badge=b.badge GROUP BY DATE_FORMAT(DATA_ORA, '%Y%m%d'));
Here is the executed version of your table and query that gives output in the order you needed, on DB-fiddle.
Try this query:
select * from EntryExitLogs where id in
(select id from EntryExitLogs where (badge,data_ora)= any
(select badge,min(data_ora)from EntryExitLogs group by date(data_ora),badge))
union
(select * from EntryExitLogs where id in
(select id from EntryExitLogs where (badge,data_ora)= any
(select badge,max(data_ora)from EntryExitLogs group by date(data_ora),badge)))
order by id;
I think its better to make use of the ID column for selecting the rows, because the timestamp column contains duplicates.
You could use a join with subquery for badge 1 and badge 2
select t1.badge, min_dat, nax_date
from (
select badge, min_(data_ora) min_data
from my_table
where lettore = 1
group by badge
) t1
INNER JOIN (
select badge, max_(data_ora) max_data
from my_table
where lettore = 2
group by badge
) t2 ON t1.badge = t2.badge

Getting last values for week in mysql

I would like know how to get the last value for each week.
Let's say I have the next values
-- Table 1 --
day value
2018-03-12 32
2018-02-14 42
2018-03-16 62
2018-03-19 82
2018-03-20 92
2018-03-21 102
2018-03-27 112
2018-03-28 122
2018-03-29 132
How can I get the next values which are the last values for each week. Assuming the week start on Monday.
Day Value
2018-03-16 62
2018-03-21 102
2018-03-29 132
I have everything settled here SQL Fiddle
You can get the week number of day then get the max value per week number.
select t1.*
from table1 t1
join (
select week(day) as wknum,
max(day) as day
from table1
group by week(day)
) t2
on t1.day=t2.day
Result:
day value
2018-03-16 62
2018-03-21 102
2018-03-29 132
You can group by YEARWEEK()
create table tbl (day date, value int);
✓
insert into tbl values
('2018-03-12', 32),
('2018-02-14', 42),
('2018-03-16', 62),
('2018-03-19', 82),
('2018-03-20', 92),
('2018-03-21', 102),
('2018-03-27', 112),
('2018-03-28', 122),
('2018-03-29', 132);
✓
select day, yearweek(day) from tbl;
day | yearweek(day)
:--------- | ------------:
2018-03-12 | 201810
2018-02-14 | 201806
2018-03-16 | 201810
2018-03-19 | 201811
2018-03-20 | 201811
2018-03-21 | 201811
2018-03-27 | 201812
2018-03-28 | 201812
2018-03-29 | 201812
select day, value
from tbl
join (select max(day) mday
from tbl
group by yearweek(day)) t
on day = mday
day | value
:--------- | ----:
2018-02-14 | 42
2018-03-16 | 62
2018-03-21 | 102
2018-03-29 | 132
dbfiddle here
This solution uses window functions and picks the latest date within the week.
https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html
I use SQL Server, but I believe this is the MySQL equivalent:
with cte AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY WEEKOFYEAR([day]) ORDER BY DAYOFWEEK([day]) DESC) AS counter_
from #table1
)
SELECT [day], [value]
FROM cte
WHERE counter_ = 1
Here's how you would do it in SQL Server - Use mysql equivalent
select b.day, b.value from (
select datepart(ww,day) a, max(day) b
from yourtable
group by datepart(ww,day))a
join yourtable b on a.a=datepart(ww,b.day) and a.b=b.day
Try this FIDDLE:
= Order by the closest to the end of every week
= Group by week
SELECT day, value
FROM (SELECT * FROM table1 ORDER BY DATEDIFF(day + INTERVAL 6 - weekday(day) DAY, day) ASC) t
GROUP BY week(day);

mysql select 2 table based on date and combine each other

i Need some help.. i have some case like this below
i have 2 table.. call ("in_table" and "out_table")
data "in_table" look like
stock_id item_id date qty_in
-----------------------------------------
1 11 2017-07-11 12
2 11 2017-07-11 10
3 12 2017-07-11 10
4 12 2017-07-19 10
And i have "out_table" is like
id_tr item_id date qty_out
-------------------------------------
1 11 2017-07-19 2
1 12 2017-07-19 1
2 11 2017-07-19 2
2 12 2017-07-19 1
And i want to combine the date and display all the data like this,
Update: the join is by item_id but i want to select by date
date item_id qty_in qty_out
---------------------------------------
2013-07-11 11 22 0
2013-07-11 12 10 0
2013-07-19 11 0 4
2013-07-19 12 10 2
Thank you for your help.
It looks like you need kind of a full outer join of two aggregate subqueries. But in your case I would get item_id and date in a union subquery (derived table) and the sums in correlated subqueries (subselect).
select item_id, date,
(select sum(qty_in) from in_table i where i.item_id = sub.item_id and i.date = sub.date) as qty_in,
(select sum(qty_out) from out_table o where o.item_id = sub.item_id and o.date = sub.date) as qty_out
from (
select item_id, date from in_table
union
select item_id, date from out_table
) sub
order by date, item_id

Select last entry for every user from log table

Hello I have problem with sql that is suppose to select last log entry per user for many users.
This is sample how my table looks like
user_id | date
--------------------
1 2013-03-06 10:00:00
17 2013-03-06 11:00:00
2 2013-03-06 10:00:00
5 2013-03-06 10:00:00
1 2013-03-06 11:00:00
17 2013-03-06 13:00:00
17 2013-03-06 13:01:00
2 2013-03-06 14:01:00
2 2013-03-06 15:00:00
2 2013-03-06 18:01:00
The result of this query is suppose to be
user_id | date
--------------------
1 2013-03-06 11:00:00
2 2013-03-06 18:01:00
5 2013-03-06 10:00:00
17 2013-03-06 13:01:00
For now I'm using this query
SELECT
a.user_id,
(SELECT b.date FROM alerts.alerts_log as b WHERE b.user_id = a.user_id ORDER BY b.date DESC LIMIT 1) as date
FROM
alerts.alerts_log as a
WHERE
a.user_id IN (1,2,5,17)
GROUP BY a.user_id
but I dont thiknk its the best one because will be too slow for many records...
can you pls suggest me better one
SELECT user_id , MAX(date)
FROM alerts.alerts_log
GROUP BY user_id;
if you have only two columns in the table, the query below will suffice your needs,
SELECT user_ID, MAX(date) max_date
FROM tableName
GROUP BY user_ID
SQLFiddle Demo
but if not and you want to get all columns within the row, you need to have subquery which separately gets the maximum date per user_ID.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT user_ID, MAX(date) max_date
FROM tableName
GROUP BY user_ID
) b ON a.user_ID = b.user_ID AND
a.date = b.max_date
SQLFiddle Demo