In 1 query: 2 results, using 2 conditions - mysql

I have table with columns type(0 or 1), amount(int)
I need query what returns 2 params: sum amount for type = 1 and sum amount for type = 0
2 queries:
SELECT SUM(amount) AS income FROM table WHERE type = 0;
SELECT SUM(amount) AS expense FROM table WHERE type = 1;
But can i return these params using only 1 query?

SELECT SUM(amount), IF(type=0, 'income', 'expense') AS type
FROM table
GROUP BY type

SELECT sum(case when type = 0
then amount
else 0
end) AS income,
sum(case when type = 1
then amount
else 0
end) AS expense
FROM table
Demo

Related

Sum on same column with two different conditions mysql

I have a table named Order with schema as
user_id, state amount
11 success 100
11 FAILED 10
11 FAILED 10
11 success 17
state can have two values (Success/Failed).
I want to fetch sum(amount) when state = "SUCCESS" - sum(amount) when state = "FAILED"
means difference total amount when success - total amount when failed.
I can solve this problem in 2 queries.
A = select id, sum(amount) when state = "SUCCESS"
B = select id, sum(amount) when state = "FAILED"
And solution will be A-B.
Is there any way I can achieve this in single sql query?
use case when
select user_id,sum(case when state = 'SUCCESS' then amount else 0 end)-sum(case when state = 'FAILED' then amount else 0 end)
from table group by user_id
Use conditional aggregation:
select id,
sum(case when state = 'SUCCESS' then amount else - amount end) as total
from t
where state in ('SUCCESS', 'FAILED')
group by id;
I assume that you want this sum per id and not overall in the table.
select sum(case when state = "SUCCESS" then amount else o end) -
sum(case when state = "FAILED" then amount else o end)
from tbl
group by userid

Count different values in a column, while doing total and group by different column values

We have a table with data from different nodes and one of the column will have status report as "compliant or non-compliant", sample data as below
I want to filter the table in such a way that if any of the checks on a node shows non compliant, it should be flagged as non-compliant and rest as compliant. Using below query i am able to do it
SELECT COUNT(*) AS total_nodes,
SUM(fully_compliant = 0) AS Non_compliant_nodes,
SUM(fully_compliant = 1) AS compliant_nodes
FROM (
SELECT Node, CASE WHEN SUM(Status = 'Compliant') = COUNT(*) THEN 1 ELSE 0 END AS fully_compliant
FROM your_table GROUP BY Node
)
Now, i want to group and split the result by dept as below, how can i achieve this
I think you're looking for this:
select dept,
count(*) as total_nodes,
sum(case when non_compliant_chk = 0 then 1 else 0 end) as compliant_nodes,
sum(case when non_compliant_chk > 0 then 1 else 0 end) as non_compliant_nodes
from (
select dept,
node,
sum(case when 'Non-Compliant' then 1 else 0 end) as non_compliant_chk
from your_table
group by dept,
node
) v
group by dept;
With few modifications to what Brian suggested, I am able to get the desired result
select dept,
count(*) as total_nodes,
sum(case when non_compliant_chk = 0 then 1 else 0 end) as compliant_nodes,
sum(case when non_compliant_chk > 0 then 1 else 0 end) as non_compliant_nodes
from (
select dept,
node,
COUNT(CASE WHEN Compliance-Status = 'Non-Compliant' THEN 1 END) 'non_compliant_chk'
from table WHERE DOR >= DATE(NOW()) - INTERVAL 7 DAY
group by Dept,
Node
) v
group by Dept;

sql query issue in record

I am getting problem in record using following query
SELECT user_id FROM temp
WHERE
(value = 1 AND field_id = 11) AND
value = 1 AND field_id = 12
Here is the table.
I should get record of 101 user_id.
Any one idea on this?
You need to aggregate by user:
SELECT user_id
FROM temp
GROUP BY user_id
HAVING
SUM(CASE WHEN value = 1 AND field_id = 11 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN value = 1 AND field_id = 12 THEN 1 ELSE 0 END) > 0;
try this sql select DISTINCT user_id from temp where value=1 and (field_id=12 or field_id=11)
You can also use where clause :
select user_id
from table t
where value = 1 and field_id in (11, 12)
group by user_id
having count(distinct field_id) = 2;

Grouping results by id and create new columns

I have a table which looks something like the following...
id price condition sell
21039 20.40 new 0
21039 20.41 used 1
12378 10.40 new 1
12378 5 used 0
45898 30.30 new 1
45898 12.20 used 0
(note: there will only ever be 1 new and used value for each id)
What I am trying to do is group all rows with the same id number but in the process creating new columns for each condition, which should look something like...
id new_price new_sell used_price new_sell
21039 20.40 0 20.41 1
12378 10.40 1 5 0
45898 30.30 1 12.20 0
All that I have come up with is the following query, which looks silly
SELECT id, price, condition,
IF(price > 3, 1, 0) AS sell
FROM products
GROUP BY id
How can I get the desired affect of the 2nd table.
This is known as a pivot table. It is done with a series of CASE statements for each column you need to produce, along with an aggregate MAX() or SUM() to eliminate NULLs and collapse it down to a single row.
SELECT
id,
SUM(CASE WHEN `condition` = 'new' THEN price ELSE 0 END) AS new_price,
SUM(CASE WHEN `condition` = 'new' THEN sell ELSE 0 END) AS new_sell,
SUM(CASE WHEN `condition` = 'used' THEN price ELSE 0 END) AS used_price,
SUM(CASE WHEN `condition` = 'used' THEN sell ELSE 0 END) AS used_sell
FROM
products
GROUP BY id
Without the SUM() and GROUP BY, you would still get 2 rows per id, with each having half its columns (not matched by condition in the CASE) as NULL. The SUM() (could also use MAX() in this case) eliminates the NULLs and produces one row since aggregate functions exclude NULL values while the GROUP BY groups the rows by id.
Here is a working sample on SQLFiddle.com
Update after comment:
To calculate sell based on the price, just replace the condition in the sell CASE statements:
SELECT
id,
SUM(CASE WHEN `condition` = 'new' THEN price ELSE 0 END) AS new_price,
SUM(CASE WHEN `condition` = 'new' AND price > 3 THEN 1 ELSE 0 END) AS new_sell,
SUM(CASE WHEN `condition` = 'used' THEN price ELSE 0 END) AS used_price,
SUM(CASE WHEN `condition` = 'used' AND price > 3 THEN 1 ELSE 0 END) AS used_sell
FROM
products
GROUP BY id
(Updated sample...)

MYSQL count function merging

In my database table I have two columns that hold either 0 or 1.
I have type and Gender, where type means 0 => teacher and 1 => student and for gender: 0 => male and 1 => female.
How can I write a single sql query to get number of teachers, students, males and females?
Right now I have:
select COUNT(type) as teachers from my_table where type = 0; // Teachers
select COUNT(type) as students from my_table where type = 1; // Students
select COUNT(gender) as males from my_table where type = 0; // Males
select COUNT(gender) as females from my_table where type = 1; // Females
Can it be done in one query? If so, how?
You can use CASE for that using SUM function:
SELECT SUM(CASE type WHEN 1 THEN 1 ELSE 0 END) AS students,
SUM(CASE type WHEN 0 THEN 1 ELSE 0 END) AS teachers,
SUM(CASE gender WHEN 1 THEN 1 ELSE 0 END) AS females,
SUM(CASE gender WHEN 0 THEN 1 ELSE 0 END) AS males
FROM my_table;
You can also use COUNT function instead of SUM like this:
SELECT COUNT(CASE type WHEN 1 THEN 1 ELSE NULL END) AS students,
COUNT(CASE type WHEN 0 THEN 1 ELSE NULL END) AS teachers,
COUNT(CASE gender WHEN 1 THEN 1 ELSE NULL END) AS females,
COUNT(CASE gender WHEN 0 THEN 1 ELSE NULL END) AS males
FROM my_table;
See this SQLFiddle
This way you can do it in a single query. If you have only two types of data in your table then you don't need to specify IN conditions in WHERE clause:
SELECT SUM(IF(type = 1, 1, 0)) as students,
SUM(IF(type = 0, 1, 0)) as teachers,
SUM(IF(gender = 1, 1, 0)) as females,
SUM(IF(gender = 0, 1, 0)) as males
FROM my_table
WHERE type IN(0,1)
AND gender IN(0,1);
You could achive this using subqueries.
SELECT COUNT(type) AS students,
(SELECT COUNT(type) FROM my_table WHERE type = 0) As teachers,
(SELECT COUNT(gender) FROM my_table WHERE gender = 1) AS females,
(SELECT COUNT(gender) FROM my_table WHERE gender = 0) AS males
FROM my_table WHERE type = 1;
Yes, you can. Did you try taking each of your SQL statements and putting them together?
SQL1 as fld1, SQL2 as fld2, someOtherFieldsIfNeeded FROM ...