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.
Related
This the example of the table name is merchant_point_log :
id created_date merchant_id point_value recent_point status
1 2022-01-02 1 5000 5000 earn
2 2022-01-02 2 3000 3000 earn
3 2022-01-02 1 3000 3000 redeem
i would like to show logging like with previous recent point in one row like :
id created_date merchant_id status previous_point point_value recent_point
1 2022-01-02 1 in 0 5000 5000
2 2022-01-02 1 out 5000 3000 2000
3 2022-01-02 2 in 0 3000 3000
how do i return previos_point column from before row of selected data ?
i already tried this query but still doesn't work as expected :
select
mpl.id
, mpl2.recent_point as previous_point
, mpl.point_value
, mpl.recent_point
from merchant_point_log mpl
left join merchant_point_log mpl2 on mpl.created_date = adddate(mpl2.created_date, 1)
order by mpl.id asc
;
the result is previous point dont return as expected it always repeat same value. I use mysql version 5.7
Here's an answer with left join for older versions where window functions are not an option.
select t.id
,t.created_date
,case t.status when 'earn' then 'in' else 'out' end as status
,coalesce(t2.recent_point, 0) as previous_point
,t.point_value
,t.recent_point
from t left join t t2 on t2.id = t.id-1
order by t.id
id
created_date
status
previous_point
point_value
recent_point
1
2022-01-02 00:00:00
in
0
2000
2000
2
2022-01-02 00:00:00
in
2000
5000
7000
3
2022-02-02 00:00:00
out
7000
3000
4000
Fiddle
We use lag to get previous_point and coalesce to put it as 0 in case previous_point is null.
select id
,created_date
,case status when 'earn' then 'in' else 'out' end as status
,coalesce(lag(recent_point) over (order by created_date), 0) as previous_point
,point_value
,recent_point
from t
id
created_date
status
previous_point
point_value
recent_point
1
2022-01-02 00:00:00
in
0
2000
2000
2
2022-01-02 00:00:00
in
2000
5000
7000
3
2022-02-02 00:00:00
out
7000
3000
4000
Fiddle
I have the following table:
id
date
type
001
2022-01-01
A
001
2022-01-03
B
001
2022-01-02
B
001
2022-02-02
A
002
2022-01-01
A
002
2022-01-03
B
004
2022-01-01
A
004
2022-01-03
B
And I need to sort the dates decending, group by ID and Type and get the time between the dates by ID and Type, either in seconds or months days
id
date
type
time diff
001
2022-01-01
A
0
001
2022-01-02
B
1
001
2022-01-03
B
1
001
2022-02-02
A
31
002
2022-01-01
A
0
002
2022-01-03
B
2
004
2022-01-01
A
0
004
2022-01-03
B
2
We can use DATEDIFF() here along with the LAG() analytic function:
SELECT id, date, type,
DATEDIFF(date, LAG(date, 1, date) OVER (PARTITION BY id ORDER BY date)) AS diff
FROM yourTable
ORDER BY id, date;
If you are using MySQL 8.0,window functions are strongly recommended. Otherwise,you might have to go a long way. Here is the query written and tested in workbench using 5.7 :
select tb1.id,tb1.date,tb1.type,ifnull(datediff(tb1.date,tb2.date),0) as 'time diff'
from
(select id,date,type, #row_id:=#row_id+1 as row_id
from
(select id,date,type
from test
group by id,date,type
order by id,date)t1,
(select #row_id:=0) t
) tb1
left join
(select id,date,type, #row_num:=#row_num+1 as row_num
from
(select id,date,type
from test
group by id,date,type
order by id,date)t2,
(select #row_num:=0) t
) tb2
on tb1.id=tb2.id and tb1.row_id-tb2.row_num=1
order by tb1.id,tb1.date
;
I have some data like below:
id
date
code
price
892
2022-02-04
B
472
891
2022-02-03
B
58
890
2022-02-02
B
467
868
2022-01-28
B
50
821
2022-01-23
B
45
780
2022-01-20
B
55
550
2022-01-14
B
79
245
2022-01-12
B
841
112
2022-01-11
B
128
91
2022-01-07
B
174
74
2022-01-04
B
64
I want to get the average price of three records, starting from previous third row to be included to current row in one SQL query, so I'm expecting like below:
id
date
code
price
avg3th
892
2022-02-04
B
472
average of ( 467+50+45)
891
2022-02-03
B
58
average of ( 50+45+55)
890
2022-02-02
B
467
average of ( 50+45+79)
868
2022-01-28
B
50
average of ( 45+79+841)
821
2022-01-23
B
45
average of ( 79+841+128)
780
2022-01-20
B
55
average of ( 841+128+174)
550
2022-01-14
B
79
...
245
2022-01-12
B
841
...
112
2022-01-11
B
128
...
91
2022-01-07
B
174
...
74
2022-01-04
B
64
...
What I have tried, using below query:
SELECT t.id, t.date, t.code, t.price,
format(
CASE WHEN
ROW_NUMBER() OVER (ORDER BY t.date) >=5 THEN
AVG ( t.price ) OVER (ORDER BY t.date
ROWS BETWEEN 4 PRECEDING AND 2 FOLLOWING)
ELSE NULL
END,0) AS average_3th
FROM test t ORDER BY t.id DESC
However, above the query still includes the first element as average (it should begin at third element), so the below result still wrong:
Any idea?
Using the row number idea average in a sub query
WITH CTE AS
(SELECT T.*,ROW_NUMBER() OVER (PARTITION BY CODE ORDER BY ID DESC) RN FROM T ),
CTE1 AS
(SELECT T.*,ROW_NUMBER() OVER (PARTITION BY CODE ORDER BY ID DESC) RN FROM T )
SELECT CTE.*,
(SELECT AVG(CTE1.PRICE) FROM CTE1 WHERE CTE1.CODE = CTE.CODE AND CTE1.RN BETWEEN CTE.RN + 2 AND CTE.RN + 4),
(SELECT GROUP_CONCAT(CTE1.ID) FROM CTE1 WHERE CTE1.CODE = CTE.CODE AND CTE1.RN BETWEEN CTE.RN + 2 AND CTE.RN + 4)
FROM CTE
ORDER BY CTE.ID DESC
;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=437342579b3165f31292e288e3165bed
For input, When quantity value greater then 1, convert in a new row with value 1 for quantity column.
INPUT
ID ProductFK Quantity Price
------------------------------------------------
10 1 2 100
11 2 3 150
12 1 1 120
OUTPUT
ID ProductFK Quantity Price
------------------------------------------------
10 1 1 100
10 1 1 100
11 2 1 150
11 2 1 150
11 2 1 150
12 1 1 120
We can do this using a sequence table trick. Inner join your current table to a sequence on the condition that the quantity be greater than or equal to the sequence value. For example:
SELECT t1.ID, t1.ProductFK, 1 AS Quantity, t1.Price
FROM yourTable t1
INNER JOIN (SELECT 1 AS Quantity UNION ALL SELECT 2 UNION ALL SELECT 3) t2
ON t1.Quantity >= t2.Quantity
ORDER BY t1.ID;
Demo
Somewhat new to SQL and I'm running into a bit of issue with a project. I have a table like this:
ID
subscription_ID
renewal_date
1
11
2022-01-01 00:00:00
2
11
2022-01-02 00:00:00
3
12
2022-01-01 00:00:00
4
12
2022-01-01 12:00:00
5
13
2022-01-01 12:00:00
6
13
2022-01-03 12:00:00
My goal is to return rows where the subscription_ID matches and the start_date is within or equal to a certain # of days (hours would work as well). For instance, I'd like rows where subscription_ID matches and the start_date is within or equal to 1 day such that my results from the table above would be:
ID
subscription_ID
renewal_date
1
11
2022-01-01 00:00:00
2
11
2022-01-02 00:00:00
3
12
2022-01-01 00:00:00
4
12
2022-01-01 12:00:00
Any assistance would be greatly appreciated--thanks!
If I understand correctly maybe you are trying something like:
select t.*
from test_tbl t
join ( SELECT subscription_id
, MAX(diff) max_diff
FROM
( SELECT x.subscription_id
, DATEDIFF(MIN(y.start_date),x.start_date) diff
FROM test_tbl x
JOIN test_tbl y ON y.subscription_id = x.subscription_id
AND y.start_date > x.start_date
GROUP BY x.subscription_id , x.start_date
) z
GROUP BY subscription_id
) as t1 on t.subscription_id=t1.subscription_id
where t1.max_diff<=1;
Result:
id subscription_id start_date
1 11 2022-01-01 00:00:00
2 11 2022-01-02 00:00:00
3 12 2022-01-01 00:00:00
4 12 2022-01-01 12:00:00
The subquery returns:
subscription_id max_diff
11 1
12 0
13 2
which is used on the where condition.
Demo