SQL+Fetch rows with latest date+Case when row_number()+Duplicates - mysql

I have a table with fields(id, date, product) with below sample data
id date Product current_Flag Expected_flag
14834 2019-01-03 00:00:00 A 1 1
14834 2019-01-31 00:00:00 B 0 0
14834 2019-02-28 00:00:00 C 0 0
14834 2019-03-30 00:00:00 C 0 0
14834 2019-01-03 00:00:00 D 0 1
I'm trying the case when row_number() over (partition by id order by date) = 1 then 1 else 0 end as flag,
But for a particular distinct Id with min date, it is getting flag as 1, but I need to flag as for a particular Id & min date and product as 1 flag as shown in Expected_flag
case when row_number() over (partition by id order by date) = 1 then 1 else 0 end as flag

You need dense_rank() instead :
case when dense_rank() over (partition by id order by date) = 1 then 1 else 0 end as Expected_flag

Related

how to aggregation without group_by in mysql?

This is table.
idx
statusIdx
date
1
1
2022-05-12 02:24
2
2
2022-05-12 02:24
3
3
2022-06-12 02:24
4
1
2022-07-12 02:24
5
1
2022-07-12 02:24
6
2
2022-07-12 02:24
How can i get like this?
stauts1
status2
status3
2022-05
1
1
0
2022-06
0
0
1
2022-07
2
1
0
sum
3
2
1
I've tried to use row_number() and count() over().
SELECT
FDATE, cnt1, cnt2, cnt3
FROM
(SELECT
DATE_FORMAT(date, "%Y.%m") AS FDATE,
COUNT(case when statusIdx=1 then 1 end) over(PARTITION BY date, statusIdx) AS cnt1,
COUNT(case when statusIdx=2 then 1 end) over(PARTITION BY date, statusIdx) AS cnt2,
COUNT(case when statusIdx=3 then 1 end) over(PARTITION BY date, statusIdx) AS cnt3,
row_number() over (PARTITION by date, statusIdx) AS rnk
FROM transfer
WHERE date betWEEN "20212-05-01" AND "2022-07-31"
ORDER BY FDATE ASC
) t
WHERE rnk = 1
It show vertically counting.
num
FDATE
cnt1
cnt2
cnt3
1
2022-05
1
0
0
1
2022-05
0
1
0
3
2022-06
0
0
1
4
2022-07
2
0
0
5
2022-07
0
1
0
How to aggregation without group_by in mysql?
Used sum() over partition. see dbfidde link if this works.

Inner Selection, Sum of colunms with conditions order by Region

After selection I get my new clear table like
SELECT a.sta_name, a.product, a.product_id, a.date, a.active, a.region_id, a.brand, a.brand_id from
(SELECT DISTINCT sta_name, product, product_id, date, active, region_id, brand, brand_id FROM `sv_ziyaret`
WHERE brand_id=2 and date between "2021-07-00" and "2021-07-31" order by region_id) a
so I get my values DISTINCT
sta_name | product | product_id | active | region_id | brand | brand_id| date |
3M A 1 1 1 A1 1 2021-07-02
2M A 1 0 1 A1 1 2021-07-02
5M B 2 0 1 A1 1 2021-07-05
4M B 2 0 2 A1 1 2021-07-06
M A 2 1 2 A1 1 2021-07-10
2M C 3 1 4 A1 1 2021-07-12
3M B 2 1 4 A1 1 2021-07-15
sta_name never repeats with same region_id, products do. What I try to get is
product_id | product | active_on | active_off | region_id
1 A 12 2 1
1 A 7 9 2
2 B 6 10 1
2 B 16 5 2
3 C 10 5 4
My main purpose is to be able to calculate percentage of product's existance in each region. In instance A product has %80 on sale on shalves at region A.
Manualy I am able to get each products result as
SELECT
product, product_id, region_id,
SUM(CASE WHEN sv_ziyaret.active = 1 THEN 1 ELSE 0 END) var,
SUM(CASE WHEN sv_ziyaret.active = 0 THEN 1 ELSE 0 END) yok
FROM
`sv_ziyaret`
WHERE
product_id=37 and date between "2021-07-00" and "2021-07-31" and region_id=7 order by region_id
but this is not a good solution I need it to be able to get each product by giving its brand_id only.
Hope to get a hand realy would same my weak
You are very close to the general solution. You just need GROUP BY AND LAST_DAY().
SELECT
product, product_id, region_id, LAST_DAY(date) month_ending,
SUM(CASE WHEN sv_ziyaret.active = 1 THEN 1 ELSE 0 END) var,
SUM(CASE WHEN sv_ziyaret.active = 0 THEN 1 ELSE 0 END) yok
FROM
sv_ziyaret
WHERE
GROUP BY product, product_id, region_id, LAST_DAY(date)
ORDER BY region_id, LAST_DAY(date), product_id;

Mysql finding count of previous date of occurences for each record

I have a table to store id, sid with a date time.
id is used as primary key and no meaning in data.
sid is used to identify entity.
eg.
id sid date
--------------------
1 1 2020-01-12
2 2 2020-01-01
3 1 2019-12-31
4 2 2019-12-31
5 1 2019-12-31
6 1 2019-11-01
7 3 2019-11-01
8 3 2018-12-21
9 2 2018-12-21
Then I would like to query for each record, count occurrences in the same table with the previous date of current date, and with the same sid, like:
id sid date previous_count
----------------------------------
1 1 2020-01-12 2
2 2 2020-01-01 1
3 1 2019-12-31 1
4 2 2019-12-31 1
5 1 2019-12-31 1
6 1 2019-11-01 0
7 3 2019-11-01 1
8 3 2018-12-21 0
9 2 2018-12-21 0
Explanation:
for row 1, since sid 1 has two records in 2019-12-31, which is the previous date of 2020-01-12 for sid 1 in the table, it has 2 in previous_count;
while in row 2, since sid 2 has only 1 record in 2019-12-31, which is the previous date of 2020-01-01 for sid 2, it has 1 in previous_count.
Thanks
Your are looking for dense_rank() - 1:
select t.*,
(dense_rank() over (partition by sid order by date) - 1) as previous_count
from t
order by id;
In older versions of MySQL, you could use variables or a correlated subquery:
select t.*,
(select count(distinct t2.date)
from t t2
where t2.sid = t.sid and t2.date < t.date
) as previous_count
from t
order by id;
EDIT:
Ahh, I think I may have misunderstood the problem. I think this does what you want:
select t.*, lag(cnt, 1, 0) over (partition by sid order by date)
from (select t.*,
count(*) over (partition by sid, date) as cnt
from t
) t
order by id;
Here is a db<>fiddle.

query to find closest lesser date

I have a table with lunch effective date and its rate.
I need to display rate from its nearest lesser effective date (created_on) for each date column.
lunch_rate table:
created_on | rate
-----------+-------
2018-06-01 | 30
2018-06-04 | 60
Here's what I tried to do:
SELECT userId,
SUM(CASE WHEN date= '2018-06-01' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-01',
SUM(CASE WHEN date= '2018-06-02' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-02',
SUM(CASE WHEN date= '2018-06-03' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-03',
SUM(CASE WHEN date= '2018-06-04' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-04'
FROM
(
SELECT userId, lunchStatus, DATE(issuedDateTime) as date
FROM `lunch_status`
WHERE DATE(issuedDateTime) BETWEEN '2018-06-01' AND '2018-06-04'
) as a
GROUP BY userId;
But this query only gives maximum rate of all, without considering the nearest effective date.
Here's the outcome:
userId | 2018-06-01 | 2018-06-02 | 2018-06-03 | 2018-06-04
------------------------------------------------------------------------
131 | 60 | 60 | 0 | 60
132 | 60 | 60 | 60 | 0
133 | 0 | 0 | 0 | 60
134 | 0 | 0 | 0 | 60
Expected outcome:
userId | 2018-06-01 | 2018-06-02 | 2018-06-03 | 2018-06-04
------------------------------------------------------------------------
131 | 30 | 30 | 0 | 60
132 | 30 | 30 | 30 | 0
133 | 0 | 0 | 0 | 60
134 | 0 | 0 | 0 | 60
SUM(CASE WHEN ... THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) ....',
How can I select lunch rate that was effective on that date?
If I understand correctly, you want the calculation in the subquery:
SELECT userId,
SUM(CASE WHEN date = '2018-06-01' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-01`,
SUM(CASE WHEN date = '2018-06-02' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-02`,
SUM(CASE WHEN date = '2018-06-03' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-03`,
SUM(CASE WHEN date = '2018-06-04' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-04`
FROM (SELECT ls.*, DATE(ls.issuedDateTime) as date
(SELECT lr.rate
FROM lunch_rate lr
WHERE DATE(lr.created_on) <= DATE(ls.issuedDateTime)
ORDER BY lr.created_on DESC
LIMIT 1
) as rate
FROM lunch_status ls
WHERE DATE(issuedDateTime) BETWEEN '2018-06-01' AND '2018-06-04'
) lr
GROUP BY lr.userId;
Note the other changes:
The subquery for lunch_rate does not use MAX(). Instead, it uses ORDER BY.
The column aliases are surrounded by backticks, not single quotes. I don't approve of the names (because they need to be escaped). But if you want them, use proper escape characters.
The tables are given reasonable aliases and column names are qualified.
You could try something like this:
SELECT lr1.rate
FROM lunch_rate lr1
WHERE lr1.created_on <= my_date
AND NOT EXISTS (SELECT *
FROM lunch_rate lr2
WHERE lr2.created_on > lr1.created_on
AND lr2.created_on <= my_date);

mysql - return row where date is equal to some value

I have table assessment as given below-
SLNO EID Period_From Period_To
1 101 2017-06-01 2017-11-14
2 102 2017-07-01 2017-09-30
3 103 2017-05-01 2017-07-31
If Period_To and currentdate is equal to 75 days then row should return 1 else 0 I used below query-
SELECT SLNO,EID, Period_From,Period_To,(CASE WHEN (PERIOD_TO = (select DATE_ADD(PERIOD_TO,INTERVAL 75 DAY))) THEN 1 ELSE 0 END) AS ASSESSMENT_ENABLE from assessment;
I got result as
SLNO EID Period_From Period_To ASSESSMENT_ENABLE
1 101 2017-06-01 2017-11-14 0
2 102 2017-07-01 2017-09-30 0
3 103 2017-05-01 2017-07-31 0
I am getting wrong result. Please help me.
i don't think you need sub query. try this it works for me
SELECT SLNO,EID, Period_From,Period_To,
(CASE WHEN (PERIOD_TO = DATE_FORMAT(CURDATE(), '%Y-%m-%d') - INTERVAL 75 DAY) THEN 1 ELSE 0 END)
AS ASSESSMENT_ENABLE
Short solution using CURRENT_DATE and DATEDIFF functions:
SELECT
SLNO, EID, Period_From, Period_To,
IF(DATEDIFF(CURRENT_DATE(), date_to) = 75, 1, 0) AS ASSESSMENT_ENABLE
FROM
ASSESSMENT
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html
You can try this-
select
SLNO,
EID,
Period_From,
Period_To,
case when (DATEDIFF(now(),PERIOD_TO)=75) then 1 else 0 end as ASSESSMENT_ENABLE
from
assessment;