amount group
--------------
100 'a'
40 'b'
30 'a'
50 'b'
query output:
diff(a-b)
---------
40
how to do it in MYSQL?
You can simply:
SELECT (SELECT SUM(amount) FROM t WHERE `group` = 'a') -
(SELECT SUM(amount) FROM t WHERE `group` = 'b') AS diff
Or:
SELECT SUM(CASE
WHEN `group` = 'a' THEN amount
WHEN `group` = 'b' THEN -amount
END) AS diff
FROM t
Related
I have 3 tables (ticket1, ticket2, ticket3) that contain same field:
ticket1: ticket2: ticket2:
======== ======== ========
ticket_id ticket_id ticket_id
status status status
And my query just like this:
("SELECT (SELECT COUNT( * ) FROM `ticket1` WHERE `status` =9) AS done,
(SELECT COUNT( * ) FROM `ticket1` WHERE `status` =10) AS Incomplete,
(SELECT COUNT( * ) FROM `ticket1` WHERE `status` =2) AS New")
This is to count ticket and filter by status.
And my question is, how i can count all ticket into total Done, Incomplete, and New from ticket1, ticket2, ticket3.
Help me guys, thanks..
I guess the 3d table's name is ticket3, right?
SELECT
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 9) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 9) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 9) AS TotalDone,
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 10) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 10) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 10) AS TotalIncomplete,
(SELECT COUNT(*) FROM `ticket1` WHERE `status` = 2) +
(SELECT COUNT(*) FROM `ticket2` WHERE `status` = 2) +
(SELECT COUNT(*) FROM `ticket3` WHERE `status` = 2) AS TotalNew
Try this.
select status, count(1) from
(select * from ticket1
union all
select * from ticket2
union all
select * from ticket3) group by status;
Let me know if you face any issues
you could select from union all
select sum(case when status = 9 then 1 else 0 end) done,
sum(case when status = 10 then 1 else 0 end) Incomplete,
sum(case when status = 2 then 1 else 0 end) New,
sum(case when status in (9,10,2) then 1 else 0 end) deon_incomplete_new,
count(*) tot
from (
select ticket_id, status from ticket1
union all
select ticket_id, status from ticket2
union all
select ticket_id, status from ticket2
) t
I would suggest:
select sum(case when status = 9 then cnt else 0 end) as done,
sum(case when status = 10 then cnt else 0 end) as incomplete,
sum(case when status = 2 then cnt else 0 end) as new
from ((select status, count(*) as cnt from ticket1 group by status
) union all
(select status, count(*) as cnt from ticket2 group by status
) union all
(select status, count(*) as cnt from ticket3 group by status
)
) t;
Or, you might consider putting the values in separate rows using group by.
If performance is an issue and you have lots of other tickets statuses (or more specifically lots of rows with different statuses), then where status in (2, 9, 10) in each of the subqueries might help.
I have a table called votes with 4 columns: id, name, choice, date.
****id****name****vote******date***
****1*****sam*******A******01-01-17
****2*****sam*******B******01-05-30
****3*****jon*******A******01-01-19
My ultimate goal is to count up all the votes, but I only want to count 1 vote per person, and specifically each person's most recent vote.
In the example above, the result should be 1 vote for A, and 1 vote for B.
Here is what I currently have:
select name,
sum(case when uniques.choice = A then 1 else 0 end) votesA,
sum(case when uniques.choice = B then 1 else 0 end) votesB
FROM (
SELECT id, name, choice, max(date)
FROM votes
GROUP BY name
) uniques;
However, this doesn't work because the subquery is indeed selecting the max date, but it's not including the correct choice that is associated with that max date.
Don't think "group by" to get the most recent vote. Think of join or some other option. Here is one way:
SELECT v.name,
SUM(v.choice = 'A') as votesA,
SUM(v.choice = 'B') as votesB
FROM votes v
WHERE v.date = (SELECT MAX(v2.date) FROM votes v2 WHERE v2.name = v.name)
GROUP BY v.name;
Here is a SQL Fiddle.
Your answer are close but need to JOIN self
Subquery get Max date by name then JOIN self.
select
sum(case when T.vote = 'A' then 1 else 0 end) votesA,
sum(case when T.vote = 'B' then 1 else 0 end) votesB
FROM (
SELECT name,Max(date) as date
FROM T
GROUP BY name
) AS T1 INNER JOIN T ON T1.date = T.date
SQLFiddle
Try this
SELECT
choice,
COUNT(1)
FROM
votes v
INNER JOIN
(
SELECT
id,
max(date)
FROM
votes
GROUP BY
name
) tmp ON
v.id = tmp.id
GROUP BY
choice;
Something like this (if you really need count only last vote of person)
SELECT
sum(case when vote='A' then cnt else 0 end) voteA,
sum(case when vote='B' then cnt else 0 end) voteB
FROM
(SELECT vote,count(distinct name) cnt
FROM (
SELECT name,vote,date,max(date) over (partition by name) maxd
FROM votes
)
WHERE date=maxd
GROUP BY vote
)
PS. MySQL v 8
select
name,
sum( case when choice = 'A' then 1 else 0 end) voteA,
sum( case when choice = 'B' then 1 else 0 end) voteB
from
(
select id, name, choice
from votes
where date = (select max(date) from votes t2
where t2.name = votes.name )
) t
group by name
Or output just one row for the total counts of VoteA and VoteB:
select
sum( case when choice = 'A' then 1 else 0 end) voteA,
sum( case when choice = 'B' then 1 else 0 end) voteB
from
(
select id, name, choice
from votes
where date = (select max(date) from votes t2
where t2.name = votes.name )
) t
Based on #d-shish solution, and since introduction (in MySQL 5.7) of ONLY_FULL_GROUP_BY, the GROUP BY statement must be placed in subquery like this :
SELECT v.`name`,
SUM(v.`choice` = 'A') as `votesA`,
SUM(v.`choice` = 'B') as `votesB`
FROM `votes` v
WHERE (
SELECT MAX(v2.`date`)
FROM `votes` v2
WHERE v2.`name` = v.`name`
GROUP BY v.`name` # << after
) = v.`date`
# GROUP BY v.`name` << before
Otherwise, it won't work anymore !
I have this kind of table (simplified):
orders sample data below
---------------------------------------------
id INT: 1 2 3 4 5
userid INT 10 10 10 20 20
status CHAR(1) A A B A C
and want to select all orders where for each userid status is IN ('A','B') but have no orders at all IN ('C','D').
So output for above data would give orders with ID=1, 2 and 3. User ID=10 have orders A and B, but no C or D.
In other words: Select orders for customers who have orders with status A or B, but none of statuses C or D.
I started with this:
SELECT
xcart_orders.orderid,
xcart_orders.*
FROM xcart_orders
JOIN (
select count(*) as bad_statuses, userid from xcart_orders
where status in ('C','D')
group by userid
) bo
ON bo.userid=xcart_orders.userid
JOIN (
select count(*) as good_statuses, userid from xcart_orders
where status in ('A','B')
group by userid
) bo2
ON bo2.userid=xcart_orders.userid
WHERE bo2.good_statuses>0 and bo.bad_statuses=0
but think count(*) won't return zero for 'bad' statuses, so I get no results.
You have an aggregation without GROUP BY and for check the result you need us HAVING instead of WHERE
SELECT
xcart_orders.orderid,
xcart_orders.*,
SUM(CASE WHEN xcart_orders.status in ('C','D') THEN 1 ELSE 0 END) AS bad_statuses,
SUM(CASE WHEN xcart_orders.status in ('A','B') THEN 1 ELSE 0 END) AS good_statuses
FROM xcart_orders
GROUP BY orderid
HAVING bad_statuses = 0
AND good_statuses > 0
Please be aware the fields you get from xcart_orders.* will be random (or non deterministc) if you need a particular one you need to order it first.
First you GROUP BY user_id to check if have any status different to 'A', 'B'
Then you select orders from those user_id:
SQL DEMO
SELECT `user_id`
FROM orders1
GROUP BY `user_id`
HAVING COUNT(*) = COUNT(CASE WHEN `status` IN ('A', 'B') THEN 1 END);
SELECT *
FROM orders1
WHERE `user_id` IN (SELECT `user_id`
FROM orders1
GROUP BY `user_id`
HAVING COUNT(*) = COUNT(CASE WHEN `status` IN ('A', 'B') THEN 1 END)
);
OUTPUT
I have 2 queries to get the count of families having count = 1 and count = 2.
SELECT Name, count(*) as c FROM Tablename GROUP BY HOUSE_NO HAVING c<=1;
SELECT Name, count(*) as c FROM Tablename GROUP BY HOUSE_NO HAVING c>=2 and c<=4;
But i need to combine those queries into single query.Like
count1 count2
nooffamiliesHavingcount = 1 nooffamiliesHavingcount = 2
Please help me....Thanks in advance..
You need to put your first count into a subquery:
SELECT COUNT(CASE WHEN C = 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN C = 2 THEN 1 END) AS nooffamiliesHavingcount2
FROM ( SELECT COUNT(*) AS C
FROM TableName
GROUP BY House_No
) t
WHERE c IN (1, 2);
EDIT
If you need to do ranges in your count you can use this:
SELECT COUNT(CASE WHEN C <= 1 THEN 1 END) AS nooffamiliesHavingcount1,
COUNT(CASE WHEN C BETWEEN 2 AND 4 THEN 1 END) AS nooffamiliesHavingcount2,
COUNT(CASE WHEN C > 4 THEN 1 END) AS nooffamiliesHavingcount3
FROM ( SELECT COUNT(*) AS C
FROM TableName
GROUP BY House_No
) t
Example on SQL Fiddle
SELECT CASE WHEN c <= 1 THEN "<=1"
WHEN c BETWEEN 2 and 4 THEN "2-4"
END familysize,
COUNT(*) nooffamilies
FROM (SELECT Name, count(*) c
FROM Tablename
GROUP BY Name) x
GROUP BY familysize
HAVING familysize IS NOT NULL
FIDDLE
have a table like this
empid questionid options
1 1 A
2 1 A
3 1 B
4 1 C
now i need result like this
questionid responseA responseB responseC
1 50% 25% 25%
You could PIVOT;
SELECT questionid, (A / total) * 100 responseA, (B / total) * 100 responseB, (C / total) * 100 responseC FROM (
SELECT T1.questionid, T1.options, T2.total
FROM the_tbl T1
INNER JOIN (SELECT questionid, CAST(COUNT(*) AS MONEY) AS total FROM the_tbl GROUP BY questionID) T2 ON T2.questionid = T1.questionid
) T
PIVOT (
COUNT(options) FOR options IN ([A], [B], [C])
) AS pvt
ORDER BY questionid
T-SQL:
SELECT
questionid,
SUM(CASE options WHEN 'A' THEN 100.0 ELSE 0.0 END) / COUNT(options) AS responseA,
SUM(CASE options WHEN 'B' THEN 100.0 ELSE 0.0 END) / COUNT(options) AS responseB,
SUM(CASE options WHEN 'C' THEN 100.0 ELSE 0.0 END) / COUNT(options) AS responseC
FROM
answers
GROUP BY
questionid
Note: To avoid casting and multiplying 100, I used 100.0 and 0.0 values in CASE ... END expressions.
SELECT CAST(100/
( SELECT COUNT(*)
FROM your_Table as t2
WHERE t2.questionid = t1.questionid )
* COUNT(*) AS VARCHAR) + '%' AS 'Percent', OPTIONS, questionid
FROM your_Table as t1
--WHERE questionid = 2
GROUP BY OPTIONS, questionid
ORDER BY questionid;
This is one possible way you could do it
(works on SQL-Server but not sure if it does in MySql)