Multiple select with single Group By query - mysql

I have these 3 fields in the table.
trans_date | transaction_type | client_id
What I need is a count of entries by transaction_types for each date. For example,
Date : 07/07/2015 total count : 6 transaction_type 1 count : 3 ,
transaction_type 2 count : 1, transaction_type 3 count : 2 etc....
And I need this for all the dates grouped by each date.
Here's my current query,
SELECT count(id) as total_count,
(select count(id) where transaction_type=1) as type1_count,
(select count(id) where transaction_type=2) as type2_count,
(select count(id) where transaction_type=3) as type3_count
FROM tblTransactions
where client_id=1
GROUP BY date(trans_date/1000, 'unixepoch')
This returns weird numbers that doesn't match. What am I doing wrong?

The reason that you are getting weird values is that your sub queries are not filtered by date so you will get the total count for each transaction type. What you need is a correlated subquery that will get a paremeter from outer query:
SELECT count(id) as total_count,
(select count(id) where transaction_type=1 and trans_date=t.trans_date) as type1_count,
(select count(id) where transaction_type=2 and trans_date=t.trans_date) as type2_count,
(select count(id) where transaction_type=3 and trans_date=t.trans_date) as type3_count
FROM tblTransactions t
where client_id=1
GROUP BY date(trans_date/1000, 'unixepoch')

You can use sum function instead of subqueries
select date(trans_date/1000, 'unixepoch') d,
sum(case when transaction_type = 1 then 1 else 0 end) type1_count,
sum(case when transaction_type = 2 then 1 else 0 end) type2_count,
sum(case when transaction_type = 3 then 1 else 0 end) type3_count
from tblTransactions
where client_id=1
group by d

Related

SQL count show group by show in column instead of rows

I have a table like this
Now my output would like to be
total_rows | completed | incomplete
------------------------------------
7 2 5
How can I achieve that.
You could use condition aggregation
select count(*) total ,
sum(completed = 1) completed ,
sum(completed = 0) incompleted
from your_table
Try the following.
select
count(*) as total_rows,
sum(case when completed = 1 then 1 else 0 end) as completed,
sum(case when completed = 0 then 1 else 0 end) as incomplete
from myTable
With conditional aggregation:
select
count(*) as total_rows,
sum(completed) completed,
sum(1 - completed) incomplete
from tablename
or:
select
count(*) as total_rows,
sum(completed) completed,
sum(not completed) incomplete
from tablename
I think this will help you
select count(id) as total_rows ,
sum(completed = 1) as completed ,
sum(completed = 0) as incompleted from sales_call_task_jo_iformation;
please try this if you need I will help you

MySql GROUP BY Max Date

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 !

Using multiple group by having in single query

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

error : #1242 - Subquery returns more than 1 row

I got an error: #1242 - Subquery returns more than 1 row when i run this sql.
CREATE VIEW test
AS
SELECT cc_name,
COUNT() AS total,
(SELECT COUNT(*)
FROM bed
WHERE respatient_id > 0
GROUP BY cc_name) AS occupied_beds,
(SELECT COUNT(*)
FROM bed
WHERE respatient_id IS NULL
GROUP BY cc_name) AS free_beds
FROM bed
GROUP BY cc_name;
The problem is that your subselects are returning more than one value - IE:
SELECT ...
(SELECT COUNT(*)
FROM bed
WHERE respatient_id IS NULL
GROUP BY cc_name) AS free_beds,
...
...will return a row for each cc_name, but SQL doesn't support compacting the resultset for the subselect - hence the error.
Don't need the subselects, this can be done using a single pass over the table using:
SELECT b.cc_name,
COUNT(*) AS total,
SUM(CASE
WHEN b.respatient_id > 0 THEN 1
ELSE 0
END) AS occupied_beds,
SUM(CASE
WHEN b.respatient_id IS NULL THEN 1
ELSE 0
END) AS free_beds
FROM bed b
GROUP BY b.cc_name
This is because your subqueries (the SELECT bits that are inside parentheses) are returning multiple rows for each outer row. The problem is with the GROUP BY; if you want to use subqueries for this, then you need to correlate them to the outer query, by specifying that they refer to the same cc_name as the outer query:
CREATE VIEW test
AS
SELECT cc_name,
COUNT() AS total,
(SELECT COUNT()
FROM bed
WHERE cc_name = bed_outer.cc_name
AND respatient_id > 0) AS occupied_beds,
(SELECT COUNT(*)
FROM bed
WHERE cc_name = bed_outer.cc_name
WHERE respatient_id IS NULL) AS free_beds
FROM bed AS bed_outer
GROUP BY cc_name;
(See http://en.wikipedia.org/wiki/Correlated_subquery for information about correlated subqueries.)
But, as OMG Ponies and a1ex07 say, you don't actually need to use subqueries for this if you don't want to.
Your subqueries return more than 1 row. I think you you need something like :
SELECT COUNT(*) AS total,
COUNT(CASE WHEN respatient_id > 0 THEN 1 END) AS occupied_beds,
COUNT(CASE WHEN respatient_id IS NULL THEN 1 END) AS free_beds
FROM bed
GROUP BY cc_name
You can also try to use WITH ROLLUP + pivoting (mostly for learning purposes, it's a much longer query ) :
SELECT cc_name,
MAX(CASE
WHEN num_1 = 1 THEN tot_num END) AS free_beds,
MAX(CASE
WHEN num_1 = 2 THEN tot_num END) AS occupied_beds,
MAX(CASE
WHEN num_1 = IS NULL THEN tot_num END) AS total
FROM
(SELECT cc_name, CASE
WHEN respatient_id > 0 THEN 1
WHEN respatient_id IS NULL THEN 2
ELSE 3 END as num_1,
COUNT(*) as tot_num
FROM bed
WHERE
CASE
WHEN respatient_id > 0 THEN 1
WHEN respatient_id IS NULL THEN 2
ELSE 3 END != 3
GROUP BY cc_name,
num_1 WITH ROLLUP)A
GROUP BY cc_name
SELECT COUNT()
FROM bed
WHERE respatient_id > 0
GROUP BY cc_name
You need to remove the group-by in the sub query, so possibly something like
SELECT COUNT(*)
FROM bed
WHERE respatient_id > 0
or possibly -- depending on what your application logic is....
SELECT COUNT(*) from (
select count(*),cc_name FROM bed
WHERE respatient_id > 0
GROUP BY cc_name) filterview

Getting a Rank out of a Total

I have been doing this for quite some time:
SELECT COUNT(*) AS 'Rank' FROM Table
WHERE Condition = 'Condition' AND Score >= 'Score';
SELECT COUNT(*) AS 'Total' FROM Table
WHERE Condition = 'Condition';
Is there a more efficient way of getting both Rank and Total?
You can calculate both at the same time with one pass through the data.
SELECT COUNT(*) AS 'Total',
SUM(CASE WHEN Score >= 'Score' THEN 1 ELSE 0 END) AS `Rank`
FROM Table
WHERE Condition = 'Condition';