show per column the value of each date_sub - mysql

I want to display the sales per month of the itemcode in one query. But the only thing I can do right now is get the total of it. Im using date_sub.
select p.itemcode, sa.quantity
from sales sa join product p on p.itemcode = sa.itemcode
where DATE >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH) and sa.quantity < 50
group by p.itemcode
The query shown above shows this output:
Itemcode quantity
694 48
7891 45
B-04.020.12405 48
B-04.020.12407 49
The output that i want to show is:
Itemcode 1 2 3 4 5 6
694 3 10 1 20 1 0
7891 3 10 1 20 1 0
B-04.020.12405 0 0 0 0 3 45
B-04.020.12407 3 10 1 20 1 0
Thanks!

The following query uses the CASE statement to check for the different ages and add the quantity accordingly:
select p.itemcode,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH) THEN sa.quantity ELSE 0
) 1,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 2 MONTH) AND DATE < DATE_SUB(CURDATE(), INTERVAL 1 MONTH) THEN sa.quantity ELSE 0
) 2,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH) AND DATE < DATE_SUB(CURDATE(), INTERVAL 2 MONTH) THEN sa.quantity ELSE 0
) 3,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 4 MONTH) AND DATE < DATE_SUB(CURDATE(), INTERVAL 3 MONTH) THEN sa.quantity ELSE 0
) 4,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH) AND DATE < DATE_SUB(CURDATE(), INTERVAL 4 MONTH) THEN sa.quantity ELSE 0
) 5,
SUM(
CASE WHEN DATE >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH) AND DATE < DATE_SUB(CURDATE(), INTERVAL 5 MONTH) THEN sa.quantity ELSE 0
) 6
from sales sa join product p on p.itemcode = sa.itemcode
where DATE >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH) and sa.quantity < 50
group by p.itemcode;

Related

To make date changes with if condition in mysql

for this my query is =
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((SalesDate = CURDATE() - INTERVAL 1 DAY) = null, SalesDate=CURDATE() - INTERVAL 2 DAY,SalesDate= CURDATE() - INTERVAL 1 DAY)
so this is my response
so in If condition I want to make sure that if the data in yesterday data is null or 0 then it will take day before yesterday
Perhaps something like this:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
FROM `tbl_sales`
GROUP BY SalesDate
HAVING SalesDate = CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
ELSE CURDATE() - INTERVAL 1 DAY END;
When you do (SalesDate = CURDATE() - INTERVAL 1 DAY) it will return false=0 and true=1. Therefore doing (SalesDate = CURDATE() - INTERVAL 1 DAY) = NULL, although it should be .. IS NULL instead of .. = NULL.. either way, it won't work. Let's inspect the CASE expression in HAVING part.
If it return 0 means there's no matching with date specified, then take 2 days before:
CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
If it has match for the date checking and return 1 BUT with NULL amount, then take 2 days before as well:
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
Else take yesterday date:
ELSE CURDATE() - INTERVAL 1 DAY END;
Demo fiddle
You need to cast your column to date:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY), CAST(SalesDate AS date) = CURDATE() - INTERVAL 2 DAY, CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY)

MySQL return value depending of date range

I don't understand why my SQL query doesn't work. I'm trying to do that :
if date is null then return 0
if date < 15 min then return 1
if date > 15 min and < 30 min then return 2
if date > 30 min and < 60 min then return 3
if date > 60 min and < 180 min then return 4
if date > 180 min then return 5
So here is my SQL query :
SELECT CASE
WHEN start_date IS NULL THEN 0
WHEN start_date < DATE_SUB(NOW(),INTERVAL 15 MINUTE) THEN 1
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE) THEN 2
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL 60 MINUTE) THEN 3
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND DATE_SUB(NOW(), INTERVAL 180 MINUTE) THEN 4
ELSE 5
END as remaining_time
FROM table
But I don't understand why when I got only the cases 0, 1 and 5. remaining_time is never in the. cases 2, 3 ,4.
Do you know why ?
Such condition will never be met, because the lower bound is greater than the higher bound:
start_date BETWEEN DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE)
You should have the bounds the other way around:
SELECT CASE
WHEN start_date IS NULL THEN 0
WHEN start_date < DATE_SUB(NOW(),INTERVAL 15 MINUTE) THEN 1
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL 15 MINUTE) THEN 2
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE) THEN 3
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 180 MINUTE) AND DATE_SUB(NOW(), INTERVAL 60 MINUTE) THEN 4
ELSE 5
END as remaining_time
FROM table
CASE stops on the first matching condition, so this can be simplified as follows:
SELECT CASE
WHEN start_date is NULL THEN 0
WHEN start_date < NOW() - INTERVAL 15 MINUTE THEN 1
WHEN start_date < NOW() - INTERVAL 30 MINUTE THEN 2
WHEN start_date < NOW() - INTERVAL 60 MINUTE THEN 3
WHEN start_date < NOW() - INTERVAL 180 MINUTE THEN 4
ELSE 5
END as remaining_time
FROM table

Get data from different timeframe

I have this query
SELECT concat(order_delivery_data.order_delivery_data_name,' sent'),
sum(case `order`.order_status when 'sent' then 1 else 0 end) '0-7 days'
FROM order_delivery_data
INNER JOIN `order` ON order_delivery_data.order_id = `order`.order_id
where order_delivery_data.order_delivery_data_name in ('Казахстан КАЗПОЧТА')
and order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
UNION
SELECT concat(order_delivery_data.order_delivery_data_name,' parcelonaplace'),
sum(case `order`.order_status when 'parcel-on-a-place' then 1 else 0 end) parcelonaplace
FROM order_delivery_data
INNER JOIN `order` ON order_delivery_data.order_id = `order`.order_id
where order_delivery_data.order_delivery_data_name in ('Казахстан КАЗПОЧТА')
and order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
Which is show 2 columns.
How get one more columns in same query like this?
Use conditional aggregation in your case statements and alter your where clause.
Depending on desired results you may need to alter the 2nd sum to use a between date range instead of just > interval of 14 days.
SELECT concat(order_delivery_data.order_delivery_data_name,' sent'),
sum(case When `order`.order_status = 'sent'
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY) then 1 else 0 end) '0-7 days',
sum(case When `order`.order_status = 'sent'
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 14 DAY) then 1 else 0 end) '8-14 days'
FROM order_delivery_data
INNER JOIN `order` ON order_delivery_data.order_id = `order`.order_id
WHERE order_delivery_data.order_delivery_data_name in ('Казахстан КАЗПОЧТА')
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 14 DAY)
UNION
SELECT concat(order_delivery_data.order_delivery_data_name,' parcelonaplace'),
sum(case when `order`.order_status = 'parcel-on-a-place'
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY) then 1 else 0 end) `parcelonaplace 0-7`,
sum(case when `order`.order_status = 'parcel-on-a-place'
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 14 DAY) then 1 else 0 end) `parcelonaplace 8-14
FROM order_delivery_data
INNER JOIN `order` ON order_delivery_data.order_id = `order`.order_id
WHERE order_delivery_data.order_delivery_data_name in ('Казахстан КАЗПОЧТА')
AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 14 DAY)

Grouping date of births in 2 month periods

I'm running a simple query that's returning the number of children turning 2 (birthday last month or next month). The following query returns a single row with count:
SELECT COUNT(*)
FROM table AS t
-- Child turning 2
AND t.dob <= DATE_SUB(NOW(), INTERVAL 23 MONTH)
AND t.dob >= DATE_SUB(NOW(), INTERVAL 25 MONTH)
I'd like to be able to build on this query and return multiple count rows, each for a 2 month period so that I can predict 2nd birthdays moving forward.
I could do something like this:
SELECT COUNT(*)
FROM table AS t
-- Child turning 2
AND t.dob <= DATE_SUB(NOW(), INTERVAL 23 MONTH)
AND t.dob >= DATE_SUB(NOW(), INTERVAL 25 MONTH)
UNION
SELECT COUNT(*)
FROM table AS t
-- Child turning 2
AND t.dob <= DATE_SUB(NOW(), INTERVAL 21 MONTH)
AND t.dob >= DATE_SUB(NOW(), INTERVAL 23 MONTH)
UNION...
But this is stupidly inefficient and very clumsy.
As an output I'd like to see something like this:
count |date range
---------------------------------
327 |2012-03-01 - 2012-04-31
---------------------------------
532 |2012-05-01 - 2012-06-31
I think I need to do something with GROUP BY but am unsure about how to go about this.
Many thanks.
select
case
when t.dob between date_sub(now(), interval 25 month) and date_sub(now(), interval 23 month) then 'between -25 and -23 month'
when t.dob between date_sub(now(), interval 22 month) and date_sub(now(), interval 20 month) then 'between -22 and -20 month'
when t.dob between date_sub(now(), interval 19 month) and date_sub(now(), interval 17 month) then 'between -19 and -17 month'
when t.dob between date_sub(now(), interval 16 month) and date_sub(now(), interval 14 month) then 'between -16 and -14 month'
end as my_ranges,
count(*)
from
t
group by my_ranges

using CASE expression in the WHERE clause and BETWEEN operator

I'm trying to fetch some rows from my table based on some condition as follow:
SELECT * FROM MyTable WHERE Date BETWEEN
CASE dayofweek(curdate())
when 1 then curdate() AND adddate(curdate(), interval 6 day)
when 2 then subdate(curdate(), interval 1 day) AND adddate(curdate(), interval 5 day)
when 3 then subdate(curdate(), interval 2 day) AND adddate(curdate(), interval 4 day)
when 4 then subdate(curdate(), interval 3 day) AND adddate(curdate(), interval 3 day)
when 5 then subdate(curdate(), interval 4 day) AND adddate(curdate(), interval 2 day)
when 6 then subdate(curdate(), interval 5 day) AND adddate(curdate(), interval 1 day)
when 7 then subdate(curdate(), interval 6 day) AND curdate()
END
but for some reason it doesn't work. it gives me a syntax error instead. how should I accomplish something like this?
Try this instead,
SELECT *
FROM MyTable
WHERE 1 =
CASE dayofweek(curdate())
when 1 then Date BETWEEN curdate() AND adddate(curdate(), interval 6 day)
when 2 then Date BETWEEN subdate(curdate(), interval 1 day) AND adddate(curdate(), interval 5 day)
when 3 then Date BETWEEN subdate(curdate(), interval 2 day) AND adddate(curdate(), interval 4 day)
when 4 then Date BETWEEN subdate(curdate(), interval 3 day) AND adddate(curdate(), interval 3 day)
when 5 then Date BETWEEN subdate(curdate(), interval 4 day) AND adddate(curdate(), interval 2 day)
when 6 then Date BETWEEN subdate(curdate(), interval 5 day) AND adddate(curdate(), interval 1 day)
when 7 then Date BETWEEN subdate(curdate(), interval 6 day) AND curdate()
END
The CASE() statement ,in this scenario, will only return two possible values: 1 and 0.
A CASE returns a value, not an expression. You must repeat the CASE statement for each side of the BETWEEN:
SELECT * FROM MyTable
WHERE Date BETWEEN
CASE dayofweek(curdate())
when 1 then curdate()
when 2 then subdate(curdate(), interval 1 day)
... etc
END
AND -- this is the "AND" for the BETWEEN values
CASE dayofweek(curdate())
when 1 then adddate(curdate(), interval 6 day)
when 2 then adddate(curdate(), interval 5 day)
... etc
END