I want to get some data from my database for the past 31 days. When column 'finalized' is NULL I want to get data from column 'today', but if column 'finalized' isn't NULL I want to get data from column 'finalized'. I always want to get the last entered row.
TABLE MyEarnings
id INT(11) AI
date datetime
today decimal(4,2) NULL
finalized decimal(4,2) NULL
id date today finalized
-----------------------------------------------
6 2016-02-04 04:52:00 0.39 NULL
5 2016-02-03 12:34:00 NULL 19.74
4 2016-02-03 12:33:00 15.96 NULL
3 2016-02-03 12:32:00 12.32 NULL
2 2016-02-02 15:16:00 NULL 9.16
1 2016-02-02 14:29:00 2.20 NULL
SQL
SELECT
date,
CASE
WHEN finalized=NULL
THEN today
WHEN finalized!=NULL
THEN finalized
END
AS earn
FROM MyEarnings
GROUP BY DATE_FORMAT(date, '%Y-%m-%d')
ORDER BY date ASC
LIMIT 0 , 31
This is what I end up with
date earn
---------------------------
2016-02-02 00:00:00 NULL
2016-02-03 00:00:00 NULL
2016-02-04 00:00:00 NULL
What I'm looking to get
date earn
----------------------------
2016-02-02 00:00:00 9.16
2016-02-03 00:00:00 19.74
2016-02-04 00:00:00 0.39
EDIT
I also want to get a summary for each month of all values in 'finalized'-column with the max 'id' for each day.
You can't compare null with !=, you should use is null and is not null like this:
SELECT
date,
CASE
WHEN finalized is null THEN today
ELSE finalized
END AS earn
FROM MyEarnings
GROUP BY DATE_FORMAT(date, '%Y-%m-%d')
ORDER BY date ASC LIMIT 0 , 31
Also, if your first condition is when its null, you don't need to check if its not null , ELSE will be enough since the opposite of null is not null
use CASE WHEN like this:
CASE
WHEN finalized IS NULL
THEN today
ELSE finalized
END
AS earn
Replace query:
SELECT date, (CASE
WHEN finalized IS NULL THEN today
ELSE finalized
END;
) AS earn
FROM MyEarnings
GROUP BY DATE_FORMAT(date, '%Y-%m-%d')
ORDER BY date ASC LIMIT 0,31
You need conditional aggregation, but it is a bit tricky. I think this does what you want:
SELECT DATE_FORMAT(date, '%Y-%m-%d'),
COALESCE(MAX(finalized), MAX(today)) as earn
FROM MyEarnings
GROUP BY DATE_FORMAT(date, '%Y-%m-%d')
ORDER BY date ASC
LIMIT 0 , 31;
This returns the maximum value of today. You may want the most recent value. If so, the simplest method is probably the GROUP_CONCAT()/SUBSTRING_INDEX() method:
SELECT DATE_FORMAT(date, '%Y-%m-%d'),
COALESCE(MAX(finalized),
SUBSTRING_INDEX(GROUP_CONCAT(today ORDER BY date DESC), ',', 1) + 0
) as earn
FROM MyEarnings
GROUP BY DATE_FORMAT(date, '%Y-%m-%d')
ORDER BY date ASC
LIMIT 0 , 31;
It is a bit yucky to convert numbers to strings and back for this purpose. Alternative methods require additional joins or using variables.
Using greatest id to determine last row added (cons: stretching traditional use of id):
SELECT DATE(me.date) date,
COALESCE(me.finalized,me.today) earn
FROM MyEarnings me
JOIN (
SELECT MAX(id) max_id
FROM MyEarnings
GROUP BY DATE(date)
ORDER BY DATE(date)
LIMIT 31
) o
ON o.max_id = me.id
Using greatest date to determine last row added (cons: possible dupes):
SELECT DATE(me.date) date,
COALESCE(me.finalized,me.today) earn
FROM MyEarnings me
JOIN (
SELECT MAX(date) max_date
FROM MyEarnings
GROUP BY DATE(date)
ORDER BY DATE(date)
LIMIT 31
) o
ON o.max_date = me.date
Related
I am implementing the cashback functionality with expiry feature. I am trying to redeem the partial amount based on early expiry date. I've already ordered the rows based on expiry date with the following mysql command.
SELECT * FROM `cashback` WHERE `user_id` = 1 and `used`= 'NO' AND IF(CONCAT(`point_expiry`) !='0000-00-00 00:00:00', `point_expiry` >= NOW(), NOW()) ORDER BY (case when CONCAT(`point_expiry`) = '0000-00-00 00:00:00' then 9999
else 1
end) ASC, `point_expiry` ASC
And the output for the following will be
id
amount
point_expiry
used
user_id
3
30
2023-02-24 00:00:00
NO
1
1
20
2023-02-25 00:00:00
NO
1
2
50
0000-00-00 00:00:00
NO
1
Now i want to redeem the value based on the above query result
Let say i want to redeem 35$ for the above result and the expected result will be
id
amount
point_expiry
used
used_amount
3
30
2023-02-24 00:00:00
NO
30
1
20
2023-02-25 00:00:00
NO
5
Here used_amount column represent the specific redeem value($35) redeemed based on amount column
Much appreciate your help!
This uses SUM(amount) OVER(ORDER BY ...) to calculate a running total and compares it to the balance -
SELECT *
FROM (
SELECT
`id`,
`amount`,
`point_expiry`,
`used`,
`amount` - GREATEST(SUM(`amount`) OVER (ORDER BY IF(`point_expiry` = '0000-00-00 00:00:00', 1, 0) ASC, `point_expiry` ASC, id ASC) - /* Here is your amount --> */ 35, 0) AS `used_amount`
FROM `cashback`
WHERE (`point_expiry` >= NOW() OR `point_expiry` = '0000-00-00 00:00:00')
AND `used` = 'NO'
AND `user_id` = 1
) t
WHERE `used_amount` > 0;
Consider I have the following table and current date is 2022-09-01:
Requirement: I want to get all users that have no event_name like cbt care in the past 14 days and onwards into the future.
I have this query:
SELECT * FROM test_table
WHERE event_name LIKE "%cbt care%"
AND start_date <= DATE_SUB(NOW(), INTERVAL 14 DAY)
;
Which returns:
The issue is that user_id = x does have a cbt care event in 2022-09-10 which is 9 days ahead of current date (2022-09-01).
How to return only users satisfy requirement posted above?
SELECT user_id,
COUNT(CASE WHEN event_name LIKE '%cbt care%' AND start_date
> CURDATE() - INTERVAL 14 day THEN 1 END) AS count_recent
FROM test_table
GROUP BY user_id
HAVING count_recent = 0;
https://www.db-fiddle.com/f/64j7L1VZsVdLYqmcQ2NrvV/0
The CASE expression returns 1 for each row with the conditions you described (a specific event name and a start date after the date 14 days ago, which includes all of the future dates too). For rows that don't match that condition, the CASE returns NULL. There's an implicit ELSE NULL in any CASE expression.
COUNT(<expr>), like many set functions, ignores NULLs. It will only count the occurrences of non-NULL values. So if the count returns 0, then the CASE returned only NULLs, which means there are no recent or future 'cbt care' events for that user.
select id
,user_id
,event_name
,start_date
from (
select *
,count(case when abs(datediff(curdate(),start_date)) <= 14 and event_name like "%cbt care%" then 1 end) over (partition by user_id) as cw
from t
) t
where cw = 0
id
user_id
event_name
start_date
0
a
cbt care
2022-06-01 20:00:00
Fiddle
I am trying to retrieve closed and opened stock prices from the first and last date per month.
For some reason, the output of the 'end_date_closed_stock_price' is NULL.
Do you know any idea why it is giving this result?
Also, could you tell me the appropriate queries to retrieve the last date of the month?
The followings are my queries and output.
Thanks in advance!
SELECT YEAR(date) AS years
, MONTH(date) AS months
, CASE WHEN date = MAX(date) THEN close END end_date_closed_stock_price
, CASE WHEN date = MIN(date) THEN open END first_date_opened_stock_price
FROM nasdaq_feb_25_1971_feb_25_2021
GROUP
BY 1,2
ORDER
BY 1 DESC;
---OUTPUT---
2020 5 NULL 9382.349609
2019 1 NULL 6947.459961
2019 2 NULL 7266.279785
2019 3 NULL 7582.290039
There is probably a more efficient solution, but this should work:
WITH dates as
(SELECT YEAR(date) as years
,MONTH(date) AS months
,MAX(date) as end_date
,MIN(date) as first_date
FROM nasdaq_feb_25_1971_feb_25_2021
GROUP BY 1, 2)
SELECT dates.years
, dates.months
, price1.close as end_date_closed_stock_price
, price2.open as first_date_opened_stock_price
FROM dates
JOIN nasdaq_feb_25_1971_feb_25_2021 price1
ON price1.date = dates.end_date
JOIN nasdaq_feb_25_1971_feb_25_2021 price2
ON price2.date = dates.first_date
ORDER
BY 1 DESC, 2 DESC;
I have a query I have been working on for a while but I cannot seem to get it down. The other answers on here work well for counting an amount with a certain date range then grouping by the date to get the count. However I need to have two columns counted and grouped by date.
For example here is the query I have tried to get to work:
(SELECT COUNT(*) arrived, DATE(arrived) date, 'arrived' AS source
FROM products
WHERE arrived BETWEEN '2016-01-01' AND '2016-01-31'
GROUP BY DATE(date)
ORDER BY date ASC)
UNION ALL
(SELECT COUNT(*) released, DATE(released) date, 'released' AS source
FROM products
WHERE released BETWEEN '2016-01-01' AND '2016-01-31'
GROUP BY DATE(date)
ORDER BY date ASC)
However this returns the following:
arrived date source
3 2016-01-12 arrived
2 2016-01-28 arrived
1 2016-01-29 arrived
1 2016-01-05 released
What I am requiring is something like this:
date arrived released
2016-01-05 0 1
2016-01-12 3 0
2016-01-28 2 0
2016-01-29 1 0
Any suggestions? Thank you.
You can apply conditional aggregation to a derived table obtained by a UNION ALL operation for 'arrived' and 'released' dates:
SELECT `date`,
COUNT(CASE WHEN type = 'arrived' THEN 1 END) AS arrived,
COUNT(CASE WHEN type = 'released' THEN 1 END) AS released
FROM (
SELECT arrived AS `date`, 'arrived' as type
FROM products
WHERE arrived BETWEEN '2016-01-01' AND '2016-01-31'
UNION ALL
SELECT released AS `date`, 'released' as type
FROM products
WHERE released BETWEEN '2016-01-01' AND '2016-01-31') AS t
GROUP BY `date`
Demo here
Below query I am using in my search
I have date range in search, when I searching data between '01/05/2012' AND '31/05/2012' date range but query return all record set.
SELECT t.created date, t.saleid sale_id, u.id user_id, NULL merchant_name, cheque_number cheque_number, u.first_name name, (
SELECT company_name
FROM users
WHERE id = u.my_charity_id)charity_name, t.campaignname website, t.campaignid campaign_id, t.mysoko_discount discount_percentage, t.discount, t.salecommission sale_commission, t.salevalue total_sale_value, t.salestatus sale_status
FROM `transaction` AS `t` , `users` AS `u`
WHERE DATE_FORMAT( t.created, '%d/%m/%Y' )
BETWEEN '01/05/2012' AND '31/05/2012'
AND t.user_id = u.id
LIMIT 0 , 30
I am looking for date range search data but result return all data from table.
date sale_id user_id
2012-04-19 00:00:00 20253305 45
2012-04-11 00:00:00 20253306 68
2012-04-23 00:00:00 20253307 68
2012-04-25 00:00:00 20253308 45
2012-04-27 00:00:00 20253309 45
2012-04-29 00:00:00 20253310 68
2012-04-30 00:00:00 20253311 45
2012-05-01 00:00:00 20253312 45
2012-05-03 00:00:00 20253313 68
2012-04-18 00:00:00 20253314 4
My search is from date range txn search (from / to date)
INPUT date format: DD/MM/YYYY
Do this:
WHERE t.created BETWEEN '2012-05-01 00:00:00' AND '2012-05-31 23:59:59' ...
MySQL will interpret '2012-05-31 23:59:59' as the appropriate DATETIME or TIMESTAMP type, allowing you to take advantage of an index on t.created.
Your problem is that your current query specifies that the string representation of t.created be between the strings '01/05/2012' and '31/05/2012'. Since you string format day-month-year, any date whose day component is between '02' and '30', inclusive, will match. (And the first of any month of May or later will match, etc.)
You could try filtering rows like this:
WHERE t.created >= '2012-05-01'
AND t.created < '2012-06-01'
If the month is specified as an argument, you could use the following calculations in the WHERE clause:
WHERE t.created >= #monthdate
AND t.created < #monthdate + INTERVAL 1 MONTH
One option:
WHERE MONTH(t.created) = 5 AND YEAR(t.created) = 2012
SELECT t.created date, t.saleid sale_id, u.id user_id, NULL merchant_name, cheque_number cheque_number, u.first_name name, (
SELECT company_name
FROM users
WHERE id = u.my_charity_id)charity_name, t.campaignname website, t.campaignid campaign_id, t.mysoko_discount discount_percentage, t.discount, t.salecommission sale_commission, t.salevalue total_sale_value, t.salestatus sale_status
FROM `transaction` AS `t` , `users` AS `u`
WHERE DATE_FORMAT( t.created, '%d/%m/%Y' )
BETWEEN STR_TO_DATE('01/05/2012','%d,%m,%Y') AND STR_TO_DATE('31/05/2012','%d,%m,%Y')
AND t.user_id = u.id
LIMIT 0 , 30