BAD FIELD ERROR in WHERE DATE CLAUSE for MySQL - mysql

Why am I getting an error with the following code:
SELECT
Hour,
SUM( CASE col WHEN '1' THEN data ELSE 0 END ) AS 'Sun',
SUM( CASE col WHEN '2' THEN data ELSE 0 END ) AS 'Mon',
SUM( CASE col WHEN '3' THEN data ELSE 0 END ) AS 'Tues',
SUM( CASE col WHEN '4' THEN data ELSE 0 END ) AS 'Wed',
SUM( CASE col WHEN '5' THEN data ELSE 0 END ) AS 'Thur',
SUM( CASE col WHEN '6' THEN data ELSE 0 END ) AS 'Fri',
SUM( CASE col WHEN '7' THEN data ELSE 0 END ) AS 'Sat'
FROM (
SELECT
HOUR(arrPurch.PurchaseDate) as HOUR,
DAYOFWEEK(arrPurch.PurchaseDate) as col,
SUM(ROUND(arrPurch.Credits * 1.85 + arrPurch.Price,0)) AS Data
FROM praisecharts_main_new.arrangementPurchases AS arrPurch
INNER JOIN praisecharts_main_new.catalog_dev_arrangements
AS catDEVarr ON arrPurch.ArrangementID = catDEVarr.ArrangementID
INNER JOIN praisecharts_main_new.members
ON arrPurch.MemberID = members.MemberID
GROUP BY HOUR(arrPurch.PurchaseDate), DAYOFWEEK(arrPurch.PurchaseDate)
) AS stats
WHERE
Hour BETWEEN 0 AND 23
-- AND arrPurch.PurchaseDate BETWEEN (CURDATE() - INTERVAL 29 DAY)
-- AND (CURDATE() - INTERVAL 1 DAY)
-- AND arrPurch.PurchaseDate > (CURDATE() - INTERVAL 1 DAY)
GROUP BY Hour WITH ROLLUP
When I don't try to PIVOT the results with the CASE clauses, I don't get an error. Here is an example of a query that works:
SELECT
DAYOFWEEK(arrPurch.PurchaseDate) AS DayWeek,
FORMAT(SUM(arrPurch.Credits*1.85+arrPurch.Price)/4,0) AS `c.Rev`
FROM
praisecharts_main_new.arrangementPurchases AS arrPurch
INNER JOIN praisecharts_main_new.catalog_dev_arrangements AS catDEVarr ON
arrPurch.ArrangementID = catDEVarr.ArrangementID
INNER JOIN praisecharts_main_new.members
ON arrPurch.MemberID = members.MemberID
WHERE arrPurch.PurchaseDate BETWEEN (CURDATE() - INTERVAL 29 DAY)
AND (CURDATE() - INTERVAL 1 DAY)
GROUP BY DayWeek WITH ROLLUP;
LIMIT 14

I was able to find the answer. I moved the WHERE clause up to the embedded SELECT cause above, rather than at the bottom. Here is an example of the code that works.
SELECT
Hour,
SUM( CASE col WHEN '1' THEN data ELSE 0 END ) AS 'Sun',
SUM( CASE col WHEN '2' THEN data ELSE 0 END ) AS 'Mon',
SUM( CASE col WHEN '3' THEN data ELSE 0 END ) AS 'Tues',
SUM( CASE col WHEN '4' THEN data ELSE 0 END ) AS 'Wed',
SUM( CASE col WHEN '5' THEN data ELSE 0 END ) AS 'Thur',
SUM( CASE col WHEN '6' THEN data ELSE 0 END ) AS 'Fri',
SUM( CASE col WHEN '7' THEN data ELSE 0 END ) AS 'Sat'
FROM (
SELECT
HOUR(arrPurch.PurchaseDate) as HOUR,
DAYOFWEEK(arrPurch.PurchaseDate) as col,
SUM(ROUND((arrPurch.Credits * 1.85 + arrPurch.Price)/4,0)) AS data
FROM praisecharts_main_new.arrangementPurchases AS arrPurch
INNER JOIN praisecharts_main_new.catalog_dev_arrangements
AS catDEVarr ON arrPurch.ArrangementID = catDEVarr.ArrangementID
INNER JOIN praisecharts_main_new.members
ON arrPurch.MemberID = members.MemberID
WHERE arrPurch.PurchaseDate BETWEEN (CURDATE() - INTERVAL 29 DAY)
AND (CURDATE() - INTERVAL 1 DAY)
GROUP BY HOUR(arrPurch.PurchaseDate),
DAYOFWEEK(arrPurch.PurchaseDate)
) AS stats
WHERE
Hour BETWEEN 0 AND 23
GROUP BY Hour WITH ROLLUP

Related

MySQL use date() in CASE statement

I am trying to use the date() function in MySQL to use only the date from a datetime format to create cases for total number of orders based on day of the week. However, when I run this query, I get a value of '0' for each case.
select
(CASE datetime WHEN date(datetime) = '2020-06-22' THEN count(order_id) ELSE 0 END) AS 'Mon'
,(CASE datetime WHEN date(datetime) = '2020-06-23' THEN count(order_id) ELSE 0 END) AS 'Tue'
,(CASE datetime WHEN date(datetime) = '2020-06-24' THEN count(order_id) ELSE 0 END) AS 'Wed'
,(CASE datetime WHEN date(datetime) = '2020-06-25' THEN count(order_id) ELSE 0 END) AS 'Thu'
,(CASE datetime WHEN date(datetime) = '2020-06-26' THEN count(order_id) ELSE 0 END) AS 'Fri'
from table;
I confirmed I do get my desired ouput for an individual date when I run the following query.
select count(order_id)
from table
where date(datetime) = '2020-06-22';
tray a query like this:
select
sum( if( weekday(datetime) = 0,1,0)) as 'Mon',
sum( if( weekday(datetime) = 1,1,0)) as 'Tue',
sum( if( weekday(datetime) = 2,1,0)) as 'Wed',
sum( if( weekday(datetime) = 3,1,0)) as 'Thu',
sum( if( weekday(datetime) = 4,1,0)) as 'Fri',
sum( if( weekday(datetime) = 5,1,0)) as 'Sat',
sum( if( weekday(datetime) = 6,1,0)) as 'Sun'
;
and you can use a
WHERE datetime BETWEEN '2020-06-22' AND '2020-06-26'
if you want to get a range of dates
MySQL has a nice feature where boolean values are treated as numbers, with 1 for true and 0 for false. So you can express the logic as:
select sum( weekday(datetime) = 0 ) as Mon,
sum( weekday(datetime) = 1 ) as Tue,
sum( weekday(datetime) = 2 ) as Wed,
sum( weekday(datetime) = 3 ) as Thu,
sum( weekday(datetime) = 4 ) as Fri,
sum( weekday(datetime) = 5 ) as Sat,
sum( weekday(datetime) = 6 ) as Sun
Or:
select sum( date(datetime) = '2020-06-22' ) as Mon,
sum( date(datetime) = '2020-06-23' ) as Tue,
sum( date(datetime) = '2020-06-24' ) as Wed,
sum( date(datetime) = '2020-06-25' ) as Thu,
sum( date(datetime) = '2020-06-26' ) as Fri,
sum( date(datetime) = '2020-06-27' ) as Sat,
sum( date(datetime) = '2020-06-28' ) as Sun
Your query doesn't work because it is an aggregation query (the COUNT()) but you have unaggregated columns in the SELECT. MySQL should be returning a parsing error -- and the most recent version does.
I also strongly discourage you from using single quotes to delimit columns. Here are three reasons:
Your column names are fine and don't need to be escaped.
Single quotes should only be used for string and date constants.
Backticks can be used if the identifiers do need to be escaped.

MYSQL Subtracting two SELECT Queries

Using MYSQL, I have written two big SELECT queries combined by a UNION, to get 2 rows, where the first row is the count for the current month, and the second row is the count for the previous month. The Query is as follows:
select * from
(select count(*) as type1 from table_x where nationality_id = 23 and month(START_DATE) = month(now())) as t1,
(select count(*) as type2 from table_x where nationality_id = 24 and month(START_DATE) = month(now())) as t2,
(select count(*) as type3 from table_x where nationality_id = 25 and month(START_DATE) = month(now())) as t3,
(select count(*) as type4 from table_x where nationality_id = 26 and month(START_DATE) = month(now())) as t4
UNION
select * from
(select count(*) as type1 from table_x where nationality_id = 23 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t1,
(select count(*) as type2 from table_x where nationality_id = 24 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t2,
(select count(*) as type3 from table_x where nationality_id = 25 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t3,
(select count(*) as type4 from table_x where nationality_id = 26 and month(START_DATE) = month(now() - INTERVAL 1 MONTH)) as t4
I want to add a third row, which is the difference between row 2 and row 1.
How can I do this with my current query?
You are obviously doing a compare between current and prior month. So, I would start with my inner pre-query aggregate getting only those transactions >= the first of the prior month AND the records within the nationality IDs you are looking for.
The inner date_sub() of DAYOFMONTH() -1 day gives you the first of the CURRENT month. By subtracting one more month, gives you the first of the LAST month.
Now you can aggregate the totals per nationality compared to current month or not. That inner query gives you all begin and end counts. Now that is wrapped to the outer and you can get all the counts in addition to the differences... Obviously you can change the column names respectively.
select
PQ.*,
PQ.ThisMonth23 - PQ.LastMonth23 = Diff23,
PQ.ThisMonth24 - PQ.LastMonth24 = Diff24,
PQ.ThisMonth25 - PQ.LastMonth25 = Diff25,
PQ.ThisMonth26 - PQ.LastMonth26 = Diff26
from
( select
sum( case when t.Nationality_id = 23 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth23,
sum( case when t.Nationality_id = 24 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth24,
sum( case when t.Nationality_id = 25 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth25,
sum( case when t.Nationality_id = 26 and month( t.StartDate ) = month( now()) then 1 else 0 end ) ThisMonth26,
sum( case when t.Nationality_id = 23 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth23,
sum( case when t.Nationality_id = 24 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth24,
sum( case when t.Nationality_id = 25 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth25,
sum( case when t.Nationality_id = 26 and month( t.StartDate ) != month( now()) then 1 else 0 end ) LastMonth26
from
table_x t
where
t.StartDate >= date_sub( date_sub( t.StartDate, interval DAYOFMONTH( t.StartDate ) -1 DAY ), interval 1 MONTH )
AND t.Nationality_id IN ( 23, 24, 25, 26 )
) PQ
I would just add that your query might be getting more than you think... You are asking for ALL records Ex: January REGARDLESS of the year, compared to ALL records December REGARDLESS of the year because all you are qualifying is based on the MONTH() and no YEAR() consideration. I am explicitly querying back only current and prior month.

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)

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

Oracle to SQLServer conversion

I have the following query in oracle so dont know how to convert into SQL Server.
WITH start_date AS
(
SELECT TO_DATE ( '01-Jan-2010'
, 'DD-Mon-YYYY'
) AS start_date
FROM dual
)
SELECT m.task_name
, COUNT (CASE WHEN TO_CHAR (d.task_date, 'DD') = '01' THEN 1 END) AS Day_1
, COUNT (CASE WHEN TO_CHAR (d.task_date, 'DD') = '02' THEN 1 END) AS Day_2
, COUNT (CASE WHEN TO_CHAR (d.task_date, 'DD') = '03' THEN 1 END) AS Day_3
...
, COUNT (CASE WHEN TO_CHAR (d.task_date, 'DD') = '31' THEN 1 END) AS Day_31
FROM task_master m
JOIN task_detail d ON m.task_id = d.task_id
JOIN start_date s ON d.task_date >= s.start_date
AND d.task_date < ADD_MONTHS (s.start_date, 1)
GROUP BY m.task_name
;
Have a look at using
DATEPART to check the day of month (use d or dd)
and
CONVERT(DATETIME,'01-Jan-2010')
for the Date
and
DATEADD to add the date use DATEADD (datepart ,number,date )