mysql SUM column on WHERE condition - mysql

Im trying to get a total sum of all the columns that meet a condition. Here is my current setup
SELECT
COUNT(order_type = 'BUY') AS buy_fill,
COUNT(order_type = 'SELL') AS sell_fill,
SUM(btc_total) AS fill_sum
FROM fill_orders
WHERE coin_id = '$coin'
AND time_stamp >= DATE_SUB(NOW(), INTERVAL 55 SECOND)
This is what I have now and its counting how many types of buy and sell orders I have and is also giving me sum of all orders but I need to the break the sum of the orders into BUY orders and SELL orders.
Heres the code that I'm trying trying to make work. I've added (btc_total WHERE order_type = 'BUY') and SUM(btc_total WHERE order_type = 'SELL')
SELECT
COUNT(order_type = 'BUY') AS buy_fill,
COUNT(order_type = 'SELL') AS sell_fill,
SUM(btc_total) AS fill_sum,
SUM(btc_total WHERE order_type = 'BUY') AS buy_total
SUM(btc_total WHERE order_type = 'SELL') AS sell_total
FROM fill_orders
WHERE coin_id = '$coin'
AND time_stamp >= DATE_SUB(NOW(), INTERVAL 55 SECOND)

Change this:
SUM(btc_total WHERE order_type = 'BUY') AS buy_total
to this:
SUM(IF(order_type='BUY',btc_total,NULL)) AS buy_total
The MySQL IF() function evaluates the first argument as a boolean, if that's TRUE, it returns the second argument, else it returns the third argument.
The IF() will be evaluated for each row, and the return from that expression will get totaled up by the SUM() aggregate.
or, use the more ANSI-standard equivalent to achieve the same result:
SUM(CASE WHEN order_type = 'BUY' THEN btc_total END) AS buy_total
This pattern is commonly referred to as "conditional aggregation".
For the "counts" we can replace COUNT with SUM, like this:
SUM(order_type = 'BUY') AS buy_fill
MySQL evaluates the equality comparison as a boolean, which returns 1, 0 or NULL, which are then totaled up by the SUM aggregate. (A COUNT of that would include zeros and ones, not just the ones.)
The above is equivalent to
SUM( CASE
WHEN order_type = 'BUY' THEN 1
WHEN order_type <> 'BUY' THEN 0
ELSE NULL
END
) AS buy_fill
If we want to use a COUNT aggregate, we could do it like this:
COUNT(IF(order_type = 'Buy',1,NULL)) AS buy_fill
(We could use any non-null value in place of 1, and get an equivalent result.)

"conditional aggregates" conventionally contain a case expression
SELECT
COUNT(CASE WHEN order_type = 'BUY' THEN order_type END) AS buy_fill
, COUNT(CASE WHEN order_type = 'SELL' THEN order_type END) AS sell_fill
, SUM(btc_total) AS fill_sum
, SUM(CASE WHEN order_type = 'BUY' THEN btc_total ELSE 0 END) AS buy_total
, SUM(CASE WHEN order_type = 'SELL' THEN btc_total ELSE 0 END) AS sell_total
FROM fill_orders
WHERE coin_id = '$coin'
AND time_stamp >= DATE_SUB(NOW(), INTERVAL 55 SECOND)

Related

MySQL : using sum in( case when ) statement shows 0 as result

new to MySQL..so pls help me out with this basic code..
i have a query something like this...
select weekofyear(id_time),
(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
and it gives correct results as--here
however i want to use sum after case when statement so that I can get total values where BO=1 and group by week of year , so i made following changes-
select weekofyear(id_time),
count(id),
#Tat1:=exp1,
#Tat2:=exp2,
#check1:=exp3,
#check2:=exp4,
sum(case when #check2=0 then
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+10))) then 1 else 0 end)
else
(case when (#Tat1>(#Tat2+30) or (#check1=1 and (#Tat1>#Tat2+20))) then 1 else 0 end)
end) as BO
from datb
where cid=18
and id_time between '2019-11-01 06:00:00' and '2019-11-25 06:00:00'
group by weekofyear(id_time)
but it always returns 0 as output.
Output --here 2
Please help , I don't know what am I doing wrong here.
Thanx !
As others have already said, session variables can be unpredictable (especially when aggregation gets mixed in). That said, it doesn't look like you're using the session variables to carry over values from one row to the next (as is often done), but to just make aliases of sorts for calculations you don't want to repeat.
A better way to handle that is just through subqueries.
SELECT woy, id, Tat1, Tat2, check1, check2
, CASE
WHEN check2=0 THEN (
CASE
WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+10))) THEN 1
ELSE 0
END
)
ELSE (
CASE WHEN (Tat1>(Tat2+30) OR (check1=1 AND (Tat1>Tat2+20))) THEN 1
ELSE 0
END
)
END AS BO
FROM (
SELECT WEEKOFYEAR(id_time) AS woy
, id
, exp1 AS Tat1
, exp2 AS Tat2
, exp3 AS check1
, exp4 AS check2
FROM datb
WHERE cid=18
AND id_time BETWEEN '2019-11-01 06:00:00' AND '2019-11-25 06:00:00'
) AS subQ
;
You can then tweak the above query for aggregation, or use it as a subquery for an aggregating outer query.

SQL using CASE in count and group by

I'm using CASE to categorize data in the table and count them but the results aren't accurate
live demo [here]
select DATE(date) as day, count(*),
count(distinct case when name = 'fruit' then 1 else 0 end) as fruits,
count(distinct case when name = 'vege' then 1 else 0 end) as vege,
count(distinct case when name = 'sweets' then 1 else 0 end) as sweets
from food
group by day
with rollup
I'm not sure if the issue is with CASE or in the string matching = because there's no 'sweets' still it counts 1?
any pointers I'd be grateful
Your problem is that COUNT counts every result that is not NULL. In your case you are using:
COUNT(distinct case when name = 'sweets' then 1 else 0 end)
So, when the name is not sweets, it counts the 0. Furthermore, since you are using DISTINCT, it counts just one or two values. You should either use SUM or remove the DISTINCT and the ELSE 0:
SELECT DATE(date) as day,
COUNT(*),
SUM(CASE WHEN name = 'fruit' THEN 1 ELSE 0 END) as fruits,
SUM(CASE WHEN name = 'vege' THEN 1 ELSE 0 END) as vege,
SUM(CASE WHEN name = 'sweets' THEN 1 ELSE 0 END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Or:
SELECT DATE(date) as day,
COUNT(*),
COUNT(CASE WHEN name = 'fruit' THEN 1 ELSE NULL END) as fruits,
COUNT(CASE WHEN name = 'vege' THEN 1 ELSE NULL END) as vege,
COUNT(CASE WHEN name = 'sweets' THEN 1 ELSE NULL END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Here is a modified sqlfiddle.
You can't group by an alias. You have to group by the expression.
group by date(date)
You can group on an Alias:
SELECT
FROM_UNIXTIME(UnixTimeField, '%Y') AS 'Year'
,FROM_UNIXTIME(UnixTimeField, '%m') AS 'Month'
FROM table p
GROUP BY Year, Month

MySQL using Sum and Case

I'm trying to create a GridView with ASP.NET connecting to a MySQL database. The data appears like below.
BusinessUnit OrderDate Canceled
UnitA 1/15/2013 N
UnitA 10/1/2013 N
UnitB 10/15/2013 N
UnitB 10/22/2013 N
UnitB 10/22/2013 N
Based on the records above, I'd like the result to appear like below
BusinessUnit TodaysOrders ThisMonthsOrders ThisYearsOrders
UnitA 0 1 2
UnitB 2 3 3
My current code is below. It's giving me error (something about DatabaseName.sum does not exist. Check the
Function Name Parsing and Resolution' section... )
Select
SUM (CASE WHEN (OrderDate)=DATE(NOW()) THEN 1 ELSE 0 END) AS TodaysOrders,
SUM (CASE WHEN YEAR(OrderDate) = YEAR(CURDATE()) AND MONTH(OrderDate) = MONTH(CURDATE()) THEN 1 ELSE 0 END) AS ThisMonthsOrders,
SUM (CASE WHEN YEAR(main_order_managers.creation_date) = YEAR(CURDATE()) THEN 1 ELSE 0 END) AS ThisYearsOrders
code continues
FROM OrderTable WHERE OrderTable.Canceled. <> 'Y';
Is Sum Case the best use here?
The error is caused by the space between function name and parenthesis
SUM (CASE WHEN ...
^^
Read more Function Name Parsing and Resolution
Try
SELECT BusinessUnit,
SUM(CASE WHEN OrderDate = CURDATE() THEN 1 ELSE 0 END) TodaysOrders,
SUM(CASE WHEN DATE_FORMAT(OrderDate, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m') THEN 1 ELSE 0 END) ThisMonthsOrders,
SUM(CASE WHEN YEAR(OrderDate) = YEAR(CURDATE()) THEN 1 ELSE 0 END) ThisYearsOrders
FROM OrderTable
WHERE Canceled <> 'Y'
GROUP BY BusinessUnit
Here is SQLFiddle demo

Trying to COUNT the same table for different values

I have a table called flags from which I'm trying to extract two COUNTs.
I'd like one COUNT for the number of flags since the start of the year and a separate COUNT for this week's allocation.
The query I'm using is as follows:
SELECT
COUNT(f1.ID) AS `Total Flags`,
COUNT(f2.ID) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
LEFT JOIN `frog_flags`.`flags` f2
ON f1.`ID` = f2.`ID`
WHERE
f2.`Datetime` > '2013-07-08 00:00:00'
AND
( f1.`Staff_ID` = '12345' AND f2.`Staff_ID` = '12345')
AND
f1.`Datetime` > '2012-09-01 00:00:00'
Even though I have data in place, it's showing 0 for both the Total Flags and the Weekly Flags.
I suspect I've confused my WHERE clauses for trying to JOIN the same table twice.
Am I using my clauses incorrectly when trying to COUNT the same table for different values?
This is a cross-tab SQL query - it's a great design pattern once you get the hang of it:
SELECT
sum( case when `Datetime`> '2012-09-01 00:00:00' then 1 else 0 end) AS `Total Flags`,
sum( case when `Datetime`> '2013-07-08 00:00:00' then 1 else 0 end) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
WHERE f1.`Staff_ID` = '12345'
You use a condition to create basically boolean flags which get summed up - this allows for a number of predefined new columns instead of rows.
You could take it further and do it for all staff simultaneously:
SELECT
f1.`Staff_ID`,
sum( case when `Datetime`> '2012-09-01 00:00:00' then 1 else 0 end) AS `Total Flags`,
sum( case when `Datetime`> '2013-07-08 00:00:00' then 1 else 0 end) AS `Weekly Flags`
FROM `frog_flags`.`flags` f1
WHERE f1.`Staff_ID` = '12345'
GROUP BY f1.`Staff_ID`

CASE Statement in SQL WHERE clause

I'm trying to fetch data from table where I'm using a CASE condition in the WHERE clause and currently I'm using following query:-
SELECT count(enq_id) AS total, sum(purchase_amount) AS purchase
FROM temp_stock
WHERE purchase_date <> '0000-00-00'
AND purchase_date < '2012-08-01'
AND (
STATUS = 'Sold'
OR STATUS = 'In Stock'
OR STATUS = 'Ref'
)
AND CASE WHEN (
STATUS = 'Sold'
)
THEN delivery_date >= '2012-08-01'
END
But it returns 0 for total and NULL for purchase.
From your comment.
I want to use Case Statement, could u pls clarify me about case statament in where clause
You can use CASE statement in WHERE like this:
SELECT count(enq_id) AS total, sum(purchase_amount) AS purchase
FROM temp_stock
WHERE purchase_date <> '0000-00-00'
AND purchase_date < '2012-08-01'
AND ( STATUS = 'Sold'
OR STATUS = 'In Stock'
OR STATUS = 'Ref')
AND CASE STATUS
WHEN 'Sold'
THEN delivery_date >= '2012-08-01'
ELSE 1=1
END
Here you need to use ELSE 1=1. otherwise you will not get desired result. For more explanation see this SQLFiddle
I don't think that CASE can work that way. What you want is a slightly more complex expression as your WHERE clause. Probably something like this:
SELECT count(enq_id) AS total, sum(purchase_amount) AS purchase
FROM temp_stock
WHERE purchase_date <> '0000-00-00'
AND purchase_date < '2012-08-01'
AND (
(STATUS = 'Sold' AND delivery_date >= '2012-08-01')
OR STATUS = 'In Stock'
OR STATUS = 'Ref'
)