Get data from different timeframe - mysql

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)

Related

MySQL last 7 days being ignored

I need to get all the Paid and Provisional Entry from the last 7 days but I keep getting everything returned. I am unsure what I am doing wrong I have read through quite a few posts on here and cant fathom what its. MySQL 5.6 if it makes any diffrence to what I have been doing.
SELECT
DATE_FORMAT(FROM_UNIXTIME(ct.entry_date),'%d/%m/%Y') AS booking_date,
cd.field_id_69 AS marriage_date,
cd.field_id_54 AS email_address,
CONCAT(cd.field_id_9, ' ', cd.field_id_10) AS bride_name,
CONCAT(cd.field_id_13, ' ', cd.field_id_14) AS groom_name,
ctco.title AS centre_and_course_date,
(SELECT DATE_FORMAT(FROM_UNIXTIME(col_id_1),'%d/%m/%Y') FROM
exp_channel_grid_field_50 cg WHERE cg.entry_id = ctco.entry_id ORDER BY
cg.row_id DESC LIMIT 1) AS course_end_date,
ct.status AS payment_status
FROM exp_channel_titles ct
JOIN exp_channel_data cd ON cd.entry_id = ct.entry_id
JOIN exp_relationships rco ON rco.parent_id = ct.entry_id AND rco.field_id = 41
JOIN exp_channel_titles ctco ON rco.child_id = ctco.entry_id
WHERE ct.channel_id = 2
AND ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY)
AND ct.status = 'Paid'
AND ct.status = 'Provisional';
There is problem in your WHERE statement
AND ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND ct.status = 'Paid' AND ct.status = 'Provisional';
The BETWEEN keyword needs to be followed by 2 dates, so ct.status = 'Paid' will be converted to DATE which return NULL. Hence your WHERE statement turns into.
AND ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND NULL AND ct.status = 'Provisional';
The result is that your query will return all data that have status = 'Provisional'.
You could try to modify the WHERE statement to
AND ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE() AND ct.status IN ('Paid', 'Provisional');
The syntax of BETWEEN is BETWEEN startdate AND enddate. You wrote:
ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND ct.status = 'Paid'
So it's using DATE_SUB(CURDATE(), INTERVAL 7 DAY) as the starting date, and ct.status = 'Paid' as the ending date. I'm surprised it's matching anything.
Change it to:
ct.entry_date BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE()
Or if you don't have any dates in the future, you can simply write:
ct.entry_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)

MySQL query difficulty

I would like your help with the following:
query 1:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
query 2:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
Is there any way to have the result like this (the queries returns different number of results):
------------------------------------
| xCode | x12WeeksAvg | x4WeeksAvg |
------------------------------------
| ... | ... | ... |
------------------------------------
Thank you!!
Split the BETWEEN condition
orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
into two parts
AND orders.O_CUSTDATE >= DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND orders.O_CUSTDATE <= DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
and rewrite it to
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
to get shorter and more readable code. Do the same for the second query.
Now the two queries differ only in two expressions
(sum(ordercont.QTY) / 12) as x12WeeksAvg
(sum(ordercont.QTY) / 4) as x4WeeksAvg
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
Given
<X>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
and
<Y>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
you can use conditional aggregation to combine the two queries:
SELECT stock.ST_CODE as xCODE,
(sum(CASE WHEN <X> THEN ordercont.QTY ELSE 0 END) / 12) as x12WeeksAvg,
(sum(CASE WHEN <Y> THEN ordercont.QTY ELSE 0 END) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
GROUP BY stock.ST_CODE
Replace <X> and <Y> accordingly.
Update
To improve the performance you can add
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
to the WHERE clause.
Also note that the condition stock.ST_CODE IS NOT NULL will convert your LEFT JOINs to INNER JOINs. So you could as well just write JOIN.
You can subquery them like this to get your desired output:
SELECT A.xCODE,
COALESCE(B.x12WeeksAvg, 'N/A') as x12WeeksAvg,
COALESCE(C.x4WeeksAvg, 'N/A') as x4WeeksAvg
FROM (SELECT DISTINCT ST_CODE as xCODE FROM stock) A
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) B ON A.xCODE = B.xCODE
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) C ON A.xCODE = C.xCODE
WHERE COALESCE(B.x12WeeksAvg, C.x4WeeksAvg) IS NOT NULL

Full join two querys

This query returned 385 strings
SELECT order_number
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
this returned 74 strings
SELECT order_number
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
How join it, that in that there are two columns
try this:
SELECT t1.order_number as order_t1, t2.order_number as order_t2 FROM
( SELECT order_number,`order`.order_id
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
) as t1
LEFT JOIN
(SELECT order_number,`order`.order_id
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
) as t2
ON t1.order_id = t2.order_id
UNION ALL
SELECT t1.order_number as order_t1, t2.order_number as order_t2 FROM
( SELECT order_number,`order`.order_id
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
) as t1
RIGHT JOIN
(SELECT order_number,`order`.order_id
FROM `order`
inner join order_delivery_data on `order`.order_id = order_delivery_data.order_id
where order_status = 'delivered' AND order_statusUpdatedAt BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
AND DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY)
and order_delivery_data_name in ('London')
) as t2
ON t1.order_id = t2.order_id;
You need to use FULL JOIN, i.e. UNION ALL when using mysql:
first_query UNION ALL second_query

I am trying to divide two select queries using sql, not sure if this is possible or not

Below is my query, I think in principle it should work, but am not sure if it is indeed possible or I am thinking too outside the box for this one.
SELECT
(SELECT `orders`.`Status`, COUNT(*) AS COUNT_2 FROM `orders` `sw_orders` WHERE STATUS = 'booking' AND Date(OrderDate) <= CURDATE() AND Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)) /
(SELECT `orders`.`Status`, COUNT(*) AS COUNT_2 FROM `orders` `sw_orders` WHERE STATUS = 'quote' AND Date(OrderDate) <= CURDATE() AND Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY))
AS result
That should return the value of 2 results where bookings is divided by quotes
SELECT count(case when STATUS = 'booking' then 1 end) /
count(case when STATUS = 'quote' then 1 end)
FROM `sw_orders`
WHERE Date(OrderDate) <= CURDATE()
AND Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
select count(status ='booking' or null) / count(status = 'quote') as result from table_name where Date(OrderDate) <= CURDATE() AND Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
Please watch out for syntax error. I have not taken care of.
SELECT
SUM(CASE WHEN STATUS = 'booking' THEN 1 ELSE 0 END) /
SUM(CASE WHEN STATUS = 'quote' THEN 1 ELSE 0 END)
FROM `sw_orders`
WHERE Date(OrderDate) <= CURDATE()
AND Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
I suppose COUNT of STATUS = 'quote' is not 0

show per column the value of each date_sub

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;