MySQL CASE Statement with multiple columns in statement list - mysql

I have this query, which I know doesn't work, but I've left it as it is as pseudo-code to help explain what I'm doing. I'm trying to get "Booking" and "Sales" totals from a Booking table by day-of-the-week for the past week. Hence, Mon1B = Bookings for Monday and Mon1S = Sales for Monday.
SELECT
CASE WEEKDAY(b.created)
WHEN 0 THEN (SELECT COUNT(uuid) as Mon1B, SUM(amount) as Mon1S)
WHEN 1 THEN (SELECT COUNT(uuid) as Tue1B, SUM(amount) as Tue1S)
WHEN 2 THEN (SELECT COUNT(uuid) as Wed1B, SUM(amount) as Wed1S)
WHEN 3 THEN (SELECT COUNT(uuid) as Thu1B, SUM(amount) as Thu1S)
WHEN 4 THEN (SELECT COUNT(uuid) as Wed1B, SUM(amount) as Wed1S)
WHEN 5 THEN (SELECT COUNT(uuid) as Wed1B, SUM(amount) as Wed1S)
WHEN 6 THEN (SELECT COUNT(uuid) as Wed1B, SUM(amount) as Wed1S)
END CASE
FROM Bookings b
WHERE b.created > '#week1Start#' and b.created <= '#week1End#'
How can something like this be done in MySQL?

Yes, but case can only return one value. You can do it like this:
SELECT sum(CASE when WEEKDAY(b.created) = 0 then 1 else 0 end) as Mon1b,
sum(case when weekday(b.created) = 0 then amount else 0 end) as Mon1S,
...
FROM Bookings b
WHERE b.created > '#week1Start#' and b.created <= '#week1End#'
You might find it easier as 7 rows, though:
select WEEKDAY(b.created), count(*) as cnt, sum(amount) as amt
from Bookings b
WHERE b.created > '#week1Start#' and b.created <= '#week1End#'
group by WEEKDAY(b.created)
order by 1

I think you want something like this:
SELECT COUNT(IF(WEEKDAY(b.created)=0,uuid,NULL)) AS Mon1B
, SUM(IF(WEEKDAY(b.created)=0,amount,NULL)) AS Mon1S
, COUNT(IF(WEEKDAY(b.created)=1,uuid,NULL)) AS Tue1B
, SUM(IF(WEEKDAY(b.created)=1,amount,NULL)) AS Tue1S
Or, if you prefer the equivalent (but lengthier) CASE expression:
SELECT COUNT(CASE WEEKDAY(b.created) WHEN 0 THEN uuid END) AS Mon1B
, SUM(CASE WEEKDAY(b.created) WHEN 0 THEN amount END) AS Mon1S
, COUNT(CASE WEEKDAY(b.created) WHEN 1 THEN uuid END) AS Tue1B
, SUM(CASE WEEKDAY(b.created) WHEN 1 THEN amount END) AS Tue1S
The result of a CASE expression is a scalar; it can't return more than one value.

SELECT WEEKDAY(b.created),
CASE
WHEN b.weekday='Monday' THEN (SELECT COUNT(b.uuid) as Mon1B, SUM(s.amount) as Mon1S from bookings b,sales s where b.day='Monday' and s.day='Monday')
WHEN b.weekday='Tuesday' THEN (SELECT COUNT(b.uuid) as Tue1B, SUM(s.amount) as Tue1 from bookings b,sales s where b.day='Tuesday' and s.day='tuesday')
WHEN b.weekday='Wednesday' THEN (SELECT COUNT(b.uuid) as Wed1B, SUM(s.amount) as Wed1S from bookings b,sales s where b.day='wednesday' and s.day='wednesday')
WHEN b.weekday='Thursday' THEN (SELECT COUNT(b.uuid) as Thu1B, SUM(s.amount) as Thu1S from bookings b,sales s where b.day='Thursday' and s.day='Thursday')
WHEN b.weekday='Friday' THEN (SELECT COUNT(b.uuid) as Fri1B, SUM(s.amount) as Fri1S from bookings b,sales s where b.day='Friday' and s.day='Friday')
WHEN b.weekday='saturaday' THEN (SELECT COUNT(b.uuid) as Sat1B, SUM(s.amount) as sat1S from bookings b,sales s where b.day='Saturaday' and s.day='Saturaday')
WHEN b.weekday='Sunday' THEN (SELECT COUNT(b.uuid) as sun1B, SUM(s.amount) as sun1S from bookings b,sales s where b.day='Sunday' and s.day='Sunday')
END CASE
FROM Bookings b
WHERE b.created > '#week1Start#' and b.created <= '#week1End#'

Related

how to get column count

i have a query like below
select project_task_id,
status_id,
sum(case when StatusID=1 then 1 else 0 end) as task_id=1,
sum(case whenStatusID=2 then 1 else 0 end) as task_id=2,
sum(case when StatusID=3 then 1 else 0 end) as task_id=3,
sum(case when StatusID=4 then 1 else 0 end) as task_id=4,
sum(case when StatusID=5 then 1 else 0 end) as task_id=5,
sum(case when StatusID=6 then 1 else 0 end) as task_id=6,
sum(case when StatusID=7 then 1 else 0 end) as task_id=7,
from"Projects".work_unit_status
group by project_task_id,status_id;
I'm getting the below attached output:
https://i.stack.imgur.com/1wfD1.png
and I want to get the below expected output:
https://i.stack.imgur.com/Zql9z.png
include zero's if the status_id is blank
please any one help on this
Try this: use the addition of all sum column
select project_task_id,status_id,
isnull(sum(case when StatusID=1 then 1 else 0 end),0)+
isnull(sum(case whenStatusID=2 then 1 else 0 end),0) +
isnullsum(case when StatusID=3 then 1 else 0 end),0) +
isnullsum(case when StatusID=4 then 1 else 0 end),0)+
isnullsum(case when StatusID=5 then 1 else 0 end),0) +
isnullsum(case when StatusID=6 then 1 else 0 end),0) +
isnullsum(case when StatusID=7 then 1 else 0 end),0) as count_status
from"Projects".work_unit_status group by project_task_id,status_id
use in with your case
with t1 as (
select project_task_id,
status_id,
sum(case when StatusID in (1,2,3,4,5,6,7) then 1 else 0)
as sum_s
from "Projects".work_unit_status
group by project_task_id,status_id
) ,
t2 as
(
select * from (
select 1 as statusid
union
select 2
union
select 3
union
select 4
union
select 5
union
select 6
union
select 7 ) t
) select t1.project_task_id,
t2.statusid,
case when t1.sum_s>0 or not null
then sum_s else 0 end as total
t2 full join t1 on t2.statusid=t1.status_id
Without knowing the exact table structure I assumed that status_id and statusId refer to the same column. (If they are different columns, we need to use StatusId in the COUNT.)
Based on the expected output, you want to count the status_id and group by project_task_id. To make sure that every status is represented for every task, first, we need to create a subquery of all possible project_task_id/status_id combinations. Then we use that with the aggregate values of the original table.
select
ps.project_task_id,
ps.status_id,
count(w.status_id) as total
from (
select distinct
project_task_id,
s.status_id
from work_unit_status
cross join (select distinct status_id from work_unit_status) s
) ps
left join work_unit_status w
on ps.project_task_id = w.project_task_id and ps.status_id = w.status_id
group by
ps.project_task_id,
ps.status_id
If you really need to hardcode the statuses from 1 to 7, use the query below.
select
ps.project_task_id,
ps.status_id,
count(w.status_id) as total
from (
select distinct
project_task_id,
s.status_id
from work_unit_status
cross join (
select 1 as status_id
union select 2
union select 3
union select 4
union select 5
union select 6
union select 7
) s
) ps
left join work_unit_status w
on ps.project_task_id = w.project_task_id and ps.status_id = w.status_id
group by
ps.project_task_id,
ps.status_id
order by
ps.project_task_id,
ps.status_id

SQL: Statement only returns subtotal of the first row

I have Sample Data like below:
and i use the below SQL statement :
select a.product_category_id, b.Favorite, c.In_Cart,d.Pre_sales_order,
sum(b.Favorite)+sum(c.In_Cart)+sum(d.Pre_sales_order) as SubTotal
from
(select distinct product_category_id
from item_activity
where last_item_status_code in (6,7,8)
) a
left join
(select product_category_id, count(last_item_status_code) as Favorite
from .item_activity
where last_item_status_code='6'
group by product_category_id
) b on a.product_category_id=b.product_category_id
left join
(select product_category_id, count(product_category_id) as In_Cart
from item_activity
where last_item_status_code='7'
group by product_category_id
) c on c.product_category_id=a.product_category_id
left join
(select product_category_id, count(product_category_id) as Pre_sales_order
from item_activity
where last_item_status_code='8'
group by product_category_id
) d on d.product_category_id=a.product_category_id
group by a.product_category_id
;
and achieved this:
But it just give me the subtotal of the first row....
Try this:
select product_category_id,
sum(case when last_item_status_code=6 then 1 else 0 end) As Favorite,
sum(case when last_item_status_code=7 then 1 else 0 end) As In_Cart,
sum(case when last_item_status_code=8 then 1 else 0 end) As Pre_sales_order,
count(last_item_status_code) as SubTotal
from item_activity
where last_item_status_code in (6,7,8)
group by product_category_id;
the product_category_id doesn't exist in other tables. So the Subtotal is resulting to NULL.
SUM(1 + NULL) == NULL. You can use IF or COALESCE to convert NULL to 0.

multiple selects on one table

I have a table called list and i have to extract the following.
fields are id and date
If date<20120401 then count on id >>>> give result
If date>20120401 then count on id >>>> give result
if there are 20 items of date<20120401 and 30 items of date>20120401 of an idnumber xyz
then the result should be...
xyz 20 30
I have done like ...
select
(select count(id) from list where id='xyz' and date<20120401) as date1,
(select count(id) from list where id='xyz' and date>20120401) as date2;
the result is 20 30
but how to print the idnumber?
SELECT
id,
SUM(CASE WHEN date < 20120401 THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN date > 20120401 THEN 1 ELSE 0 END) AS date2,
FROM list
WHERE id = 'xyz'
GROUP BY id
UPDATE:
SELECT
list.id,
idmaster.idlocation,
SUM(CASE WHEN list.date < 20120401 THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN list.date > 20120401 THEN 1 ELSE 0 END) AS date2,
FROM list
INNER JOIN idmaster ON list.id = idmaster.idnumber
WHERE list.id = 'xyz'
GROUP BY id
Try
select id, count(id) from list where id='xyz' and date < 20120401
union
select id, count(id) from list where id='xyz' and date > 20120401
You are looking for GROUP BY clause and maybe something like this:
SELECT
l2.id,
(SELECT COUNT(id)
FROM list l1
WHERE l1.id = l2.id AND date < 20120401) AS date1,
(SELECT COUNT(id)
FROM list l1
WHERE l1.id = l2.id AND date > 20120401) AS date2
FROM
list l2
GROUP BY
l2.id
There are more cost effective methods to get desired result, but this is the easiest to understand.
Try this:
SELECT
id,
SUM(CASE WHEN date < 20120401
THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN date > 20120401
THEN 1 ELSE 0 END) AS date2,
FROM list
WHERE id = 'xyz'
GROUP BY id

most recent entry made in table bases on one year interval mysql

Using the following sqlfiddle here How would I find the most recent payment made between the months of 2012-04-1 and 2012-03-31 using the case statement as in the previous queries
I tried this:
max(case when py.pay_date >= STR_TO_DATE(CONCAT(2012, '-04-01'),'%Y-%m-%d') and py.pay_date <= STR_TO_DATE(CONCAT(2012, '-03-31'), '%Y-%m-%d') + interval 1 year then py.amount end) CURRENT_PAY
However the answer I am getting is incorrect, where the actual answer should be:(12, '2012-12-12', 20, 1)
Please Provide me with some assistance, thank you.
Rather than a CASE inside your MAX() aggregate, that condition belongs in the WHERE clause. This joins against a subquery which pulls the most recent payment per person_id by joining on MAX(pay_date), person_id.
SELECT payment.*
FROM
payment
JOIN (
SELECT MAX(pay_date) AS pay_date, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id
) maxp ON payment.person_id = maxp.person_id AND payment.pay_date = maxp.pay_date
Here is an updated fiddle with the ids corrected in your table (since a bunch of them were 15). This returns record 18, for 2013-03-28.
Update
After seeing the correct SQL fiddle... To incorporate the results of this query into your existing one, you can LEFT JOIN against it as a subquery on p.id.
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then py.amount end) april_amount,
(case when max(py.pay_date)and month(py.pay_date)= 4 then py.amount else 0 end) max_pay_april,
sum(case
when Month(py.pay_date) = Month(curdate())
then py.amount end) current_month_amount,
sum(case
when Month(py.pay_date) = Month(curdate())-1
then py.amount end) previous_month_amount,
maxp.pay_date AS last_pay_date,
maxp.amount AS last_pay_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
/* LEFT JOIN against the subquery: */
left join (
SELECT MAX(pay_date) AS pay_date, amount, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id, amount
) maxp ON maxp.person_id = p.id
group by p.name,
v.v_name

MYSQL sum of a field depending on the value of other field

I am trying to create a field as
1.sum the purchases field where value of purchases type=vat as purchases_vat
2.sum the purchase field where value of purchase type=exempt as purchases_exempt
source table & result table example in attached image
example table
How about this?
SUM(CASE WHEN purchases_type='vat' THEN Purchases ELSE 0 END) AS purchases_vat,
SUM(CASE WHEN purchases_type='exempt' THEN Purchases ELSE 0 END) AS purchases_exempt,
Two row version:
SELECT 'vat', SUM(purchases)
FROM source_table
WHERE purchase_type = 'vat4'
UNION
SELECT 'exempt', SUM(purchases)
FROM source_table
WHERE purchase_type = 'exempt';
One row:
SELECT
(SELECT sum(purchases) from source_table where purchase_type = 'vat4') purchase_vat,
(SELECT sum(purchases) from source_table where purchase_type = 'exempt') purchase_exempt;
This will give you the sum of purchases for 'vat'. You can similarly do this for 'exempt'
SELECT `s` FROM (SELECT SUM(purchases), type FROM my_table GROUP BY type) as T1 WHERE T1.type = 'vat
select
sum(case when purchase_type = 'vat4' then purchases else 0 end) as purchase_vat4,
sum(case when purchase_type = 'exempt' then purchases else 0 end) as purchase_exempt
from source_table