SQL count show group by show in column instead of rows - mysql

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

Related

req_type wise count id in one query

I have an sql query problem . I don't want to execute three times query for same result.
In my table I have one field req_type which have three parameter ,
either 1, either 2, either 3 .
I want counter based on req_type in one query instead of by executing query 3 times like below
select count(id) as premium FROM tablename where req_type=1
select count(id) as premium1 FROm tablename where req_type=2
select count(id) as premium2 FROm tablename where req_type=3
I am stuck , can anybody help me?
You could use case for such type of count
select sum(case when req_type=1 then 1 else 0 end) as premium,
sum(case when req_type=2 then 1 else 0 end) as premium1,
sum(case when req_type=3 then 1 else 0 end) as premium2
FROM tablename
Use one query instead of threes by using group by cluase
select req_type , count(id) as premium
FROM tablename
where req_type in (1,2,3)
group by req_type
Use a GROUP BY
SELECT req_type, COUNT(id) AS count_premium
FROM tablename
GROUP BY req_type;

get value of columns in previous row and add to the next columns of the next row

I will create a graph of population by gender every year, and the graph looks like the image below.
But I'm having a hard time with the query.
Query
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
Result
In the result, 2016 male count is 4 and female count is 8. In 2017, I want the male count of 2016 to be added on the male count on 2017, meaning 2017 male count will be 5, same with female count and total count. I provided an image below of what the result should look like. Can you help me how to do this for me to proceed on doing the graph? Or is there any other way to achieve this?
Try this:
SELECT
year_added,
#malecount_v := #malecount_v + malecount as malecount,
#femalecount_v := #femalecount_v + femalecount as femalecount,
#totalcount_v := #totalcount_v + totalcount as totalcount
FROM (
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
ORDER BY year_added
) t1
CROSS JOIN (SELECT #malecount_v := 0, #femalecount_v := 0, #totalcount_v := 0) t2
In Mysql you can do it with variables, like:
SELECT
year_added,
(#iMalecount := (COUNT(CASE WHEN gender = 'Male' THEN 1 END) + #iMalecount)) AS malecount,
(#iFemalecount := (COUNT(CASE WHEN gender = 'Female' THEN 1 END) + #iFemalecount)) AS femalecount,
(#iTotalcount := (COUNT(gender) + #iTotalcount)) AS totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
but is not 100% fiable as you can read in the documentation.
In other SQL flavour probably you need a stored procedure.
you can simply use
WITH TableCount AS
(
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
)
And after that use following query
SELECT
SUM(malecount) as 'malecount',
SUM(femalecount) as 'femalecount',
SUM(totalcount) as 'totalcount'
FROM TableCount
If you are using MySql you can use temporary table to do something like CTE
CREATE TEMPORARY TABLE IF NOT EXISTS TableCount AS (
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
)
And then you can use above query
SELECT
SUM(malecount) as 'malecount',
SUM(femalecount) as 'femalecount',
SUM(totalcount) as 'totalcount'
FROM TableCount
You can use the TEMPORARY keyword when creating a table. A TEMPORARY
table is visible only to the current session, and is dropped
automatically when the session is closed. This means that two
different sessions can use the same temporary table name without
conflicting with each other or with an existing non-TEMPORARY table of
the same name. (The existing table is hidden until the temporary table
is dropped.) To create temporary tables, you must have the CREATE
TEMPORARY TABLES privilege.
By using temporary table concept you can achieve common table expression kind of functionality in MySql

Multiple select with single Group By query

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

Display the results in 1 row and different columns

Assume a simple case e.g. a table bug that has a column status that can be open,fixed etc.
If I want to know how many bugs are open I simply do:
select count(*) as open_bugs from bugs where status = 'open';
If I want to know how many bugs are open I simply do:
select count(*) as closed_bugs from bugs where status = 'closed';
If what want to know how many open and how many closed there are in a query that returns the results in 2 columns i.e.
Open | Closed|
60 180
What is the best way to do it? UNION concatenates the results so it is not what I want
This can be done by using a CASE expression with your aggregate function. This will convert the rows into columns:
select
sum(case when status = 'open' then 1 else 0 end) open_bugs,
sum(case when status = 'closed' then 1 else 0 end) closed_bugs
from bugs
This could also be written using your original queries:
select
max(case when status = 'open' then total end) open_bugs,
max(case when status = 'closed' then total end) closed_bugs
from
(
select status, count(*) as total from bugs where status = 'open' group by status
union all
select status, count(*) as total from bugs where status = 'closed' group by status
) d
Besides the CASE variants that aggregate over the whole table, there is another way. To use the queries you have and put them inside another SELECT:
SELECT
( SELECT COUNT(*) FROM bugs WHERE status = 'open') AS open_bugs,
( SELECT COUNT(*) FROM bugs WHERE status = 'closed') AS closed_bugs
FROM dual -- this line is optional
;
It has the advantage that you can wrap counts from different tables or joins in a single query.
There may also be differences in efficiency (worse or better). Test with your tables and indexes.
You can also use GROUP BY to get all the counts in separate rows (like the UNION you mention) and then use another aggregation to pivot the results in one row:
SELECT
MIN(CASE WHEN status = 'open' THEN cnt END) AS open_bugs,
MIN(CASE WHEN status = 'closed' THEN cnt END) AS closed_bugs
FROM
( SELECT status, COUNT(*) AS cnt
FROM bugs
WHERE status IN ('open', 'closed')
GROUP BY status
) AS g
Try this
select count(case when status = 'open' then 1 end) open_bugs,
count(case when status = 'closed' then 1 end) closed_bugs
from bugs

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