Combining data in SQL Union syntax - mysql

I'm doing a SQL Union syntax and I wanted to have a result like this:
+---------------+-----+---------+
|trkBusinessUnit| New | Pending |
+---------------+-----+---------+
| AIIB 2 0 |
| Credit Control 1 3 |
| Direct Center 1 2 |
| Financial Ins 1 1 |
| Motor Acclaim 1 0 |
+-------------------------------+
from my code:
SELECT trkBusinessUnit, Count(*) as New,0 as Pending
FROM tblDTPTracker
WHERE trkStatus = 'New'
GROUP BY trkBusinessUnit
UNION
SELECT trkBusinessUnit,0 as New,Count(*) as Pending
FROM tblDTPTracker
WHERE trkStatus = 'Pending'
GROUP BY trkBusinessUnit
but then the current output is:
+---------------+-----+---------+
|trkBusinessUnit| New | Pending |
+---------------+-----+---------+
| AIIB 2 0 |
| Credit Control 1 0 |
| Credit Control 0 3 |
| Direct Center 1 0 |
| Direct Center 0 2 |
| Financial Ins 1 0 |
| Financial Ins 0 1 |
| Motor Acclaim 1 0 |
+-------------------------------+
Am I missing out something or doing something wrong? Kindly advise.

There are (or has been) some syntax issues in the previous answers, but the intent of both earlier answers is correct, you need to use a GROUP BY query and NOT use UNION - which simply does not do what you were hoping/expecting.
UNION or UNION ALL work ROW by ROW, and absolutely do NOT merge by COLUMN
So, the MySQL syntax for the group by based query could be any of these:
COUNT() using an implicit NULL
SELECT
trkBusinessUnit
, COUNT(CASE WHEN trkStatus = 'New' THEN 1 END) as New
, COUNT(CASE WHEN trkStatus = 'Pending' THEN 1 END) as Pending
FROM tblDTPTracker
GROUP BY trkBusinessUnit
;
COUNT() using explicit NULL
SELECT
trkBusinessUnit
, COUNT(CASE WHEN trkStatus = 'New' THEN 1 ELSE NULL END) as New
, COUNT(CASE WHEN trkStatus = 'Pending' THEN 1 ELSE NULL END) as Pending
FROM tblDTPTracker
GROUP BY trkBusinessUnit
;
SUM() as an alternative to counting:
select
trkBusinessUnit
, sum(case when trkStatus = 'New' then 1 else 0 end) as New
, sum(case when trkStatus = 'Pending' then 1 else 0 end) as Pending
from tblDTPTracker
where trkStatus in ('Pending', 'New')
group by trkBusinessUnit
;
Apologies to both Marc Gravell & Daniel Gadawski who preceded this answer; this answer is a derivative of yours.
See this SQLFiddle demo of these queries

If I understand you correctly, you don't have to use an union.
Try:
SELECT
trkBusinessUnit,
COUNT(CASE WHEN trkStatus = 'New' THEN 1 ELSE NULL END) as New,
COUNT(CASE WHEN trkStatus = 'Pending' THEN 1 ELSE NULL END) as Pending
FROM tblDTPTracker
GROUP BY trkBusinessUnit

Union appends rows vertically (noting that UNION also takes only the distinct rows; UNION ALL takes all rows). What you want is either a full outer join of two sub-queries, or a more complicated select. I'd go with the latter!
select tblDTPTracker,
sum(case trkStatus when 'New' then 1 else 0 end) as New,
sum(case trkStatus when 'Pending' then 1 else 0 end) as Pending
from tblDTPTracker
where trkStatus in ('Pending', 'New')
group by tblDTPTracker
The full outer join approach would be something like:
SELECT ISNULL(x.trkBusinessUnit, y.trkBusinessUnit) as trkBusinessUnit,
ISNULL(x.New, 0) as New,
ISNULL(y.Pending, 0) as Pending
FROM (
SELECT trkBusinessUnit, Count(1) as New
FROM tblDTPTracker
WHERE trkStatus = 'New'
GROUP BY trkBusinessUnit) x
FULL OUTER JOIN (
SELECT trkBusinessUnit, Count(1) as Pending
FROM tblDTPTracker
WHERE trkStatus = 'Pending'
GROUP BY trkBusinessUnit) y on y.trkBusinessUnit = x.trkBusinessUnit

Related

join mysql select queries as 1 then group by

Using information of this site I have been able to do the join but im having the issues doing the group by
is there a way to get the below statements to run as 1
Query1
SELECT count(location),date
from `filter`
where location != "red"
group by date
Query2
SELECT count(location),date
from `filter`
where location = "red"
group by date
I did try the below but it outputs the wrong data
Query3
SELECT
date,
(select count(location) from `filter` where location != "red") AS indoor,
(select count(location) from `filter` where location = "red") AS outdoor
from `filter` group by date;
SQL Fiddle for each query
http://sqlfiddle.com/#!9/17ebea/4 (query1)
http://sqlfiddle.com/#!9/17ebea/6 (query2)
http://sqlfiddle.com/#!9/90c945/1 (query3)
SELECT
date,
COUNT(CASE WHEN location <> 'red' THEN location ELSE NULL END) AS indoor,
COUNT(CASE WHEN location = 'red' THEN location ELSE NULL END) AS outdoor
FROM filter
GROUP BY date;
https://dev.mysql.com/doc/refman/8.0/en/control-flow-functions.html#operator_case
You can do conditional aggregation using CASE.. WHEN expressions.
SELECT
date,
COUNT(CASE WHEN location = 'red' THEN location END) AS outdoor,
COUNT(CASE WHEN location <> 'red' THEN location END) AS indoor
FROM `filter`
GROUP BY date;
View on DB Fiddle
Result
| date | outdoor | indoor |
| ---------- | ------- | ------ |
| 2018-11-14 | 1 | 4 |
| 2018-11-15 | 1 | 0 |
| 2018-11-16 | 0 | 3 |
| 2018-11-17 | 1 | 1 |
| 2018-11-18 | 0 | 1 |
| 2018-11-19 | 0 | 2 |
| 2018-11-20 | 0 | 1 |
You can also use the following other variants, like using COUNT(1) instead, or using SUM(..) function.
Alternative #1
SELECT
date,
COUNT(CASE WHEN location = 'red' THEN 1 END) AS outdoor,
COUNT(CASE WHEN location <> 'red' THEN 1 END) AS indoor
FROM `filter`
GROUP BY date;
Alternative #2
SELECT
date,
SUM(CASE WHEN location = 'red' THEN 1 ELSE 0 END) AS outdoor,
SUM(CASE WHEN location <> 'red' THEN 1 ELSE 0 END) AS indoor
FROM `filter`
GROUP BY date;
In MySQL, I would use the shortcut that allows you to sum() boolean variables:
select date, sum(location = 'red') as red,
sum(location <> 'red') as not_red
from filter
group by date ;
Notes:
Use single quotes for string and date constants -- not double quotes. Single quotes are the standard delimiter.
<> is the SQL inequality operator, although != is also supported by most databases.
This does not count NULL values.
To handle NULL values, you might want:
sum(not location <=> 'red') as not_red

Select Count of Certain Rows as Column

I have a table with a "status" column which accepts a TINYINT. For example:
name | status
-------+--------
john | 0
joe | 1
johann | 0
jan | 1
jane | 0
How can I get a count of who is status 1 and who is status 0?
status1 | status0
--------+--------
2 | 3
Just use conditional aggregation:
select sum(status = 1) as status1, sum(status = 0) as status0
from t;
In your case, you could also write this as:
select sum(status) as status1, sum(1 - status) as status0
from t;
I would use a CASE statement to check for your value.
SELECT SUM(CASE WHEN [status] = 1 THEN 1 ELSE 0 END) AS Status1,
SUM(CASE WHEN [status] = 0 THEN 1 ELSE 0 END) AS Status0
FROM tbl;

Convert SQL rows to columns

This is my table:
id | num | comment
---+-----+--------
3 | 10 | hello
3 | 20 | pls
3 | 30 | respond
7 | 10 | leet
7 | 20 | hax
7 | 30 | zor
How can I query it out in this manner:
id | first | second | third
---+-------+--------+--------
3 | hello | pls | respond
7 | leet | hax | zor
In the event that the num column does not reliably always start at 10 and ascend by 10 you can use the following to establish a row number that restarts at each change in ID, that way you can use the rownumbers in conjunction with conditional aggregation to show each comment. The following would do so for up to 10 comments per ID, and the NUM column does not have to be 10/20/30/40/50/60/70/80/90 (it could be anything).
If the NUM column reliably starts at 10 and ascends by 10, this question has been asked and answered: How to pivot rows into columns (custom pivoting)
select id,
max(case when row_number = 1 then comment else null end) as c01,
max(case when row_number = 2 then comment else null end) as c02,
max(case when row_number = 3 then comment else null end) as c03,
max(case when row_number = 4 then comment else null end) as c04,
max(case when row_number = 5 then comment else null end) as c05,
max(case when row_number = 6 then comment else null end) as c06,
max(case when row_number = 7 then comment else null end) as c07,
max(case when row_number = 8 then comment else null end) as c08,
max(case when row_number = 9 then comment else null end) as c09,
max(case when row_number = 10 then comment else null end) as c10
from(
select #row_number := case when #prev_val = id then #row_number+1 else 1 end as row_number,
id,
comment,
#prev_val:=id as prev_val
from tbl, (select #row_number:=0,#prev_val:='') x
order by id, num) x
group by id
order by id

combining multiple different sql into one

cusID | Name | status | Date
---------------------------------
1 | AA | 0 | 2013-01-25
2 | BB | 1 | 2013-01-23
3 | CC | 1 | 2013-01-20
SELECT COUNT(cusID) FROM customer WHERE STATUS=0;
SELECT COUNT(cusID) FROM customer WHERE STATUS=1;
Is there a way of combing such two sql and return the results as one. Because want to avoid calling to DB everytime. I tried UNION of two statments, but only showing one result.
This is the shortest possible solution in MySQL.
SELECT SUM(status = 1) totalActive,
SUM(status = 0) totalInactive
FROM tableName
SQLFiddle Demo
and this is the CASE version
SELECT SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) totalActive,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) totalInactive
FROM tableName
SQLFiddle Demo

Exclude duplicate rows in query result

I want to count the number of records in database from more than two tables that are joined.
For example I have a table like this.
table
jobd + name
1 | jobA
2 | jobB
tableA
imgeid + orderid + jobid
1 | 1 | 1
2 | 2 | 1
3 | 3 | 1
4 | 4 | 1 (this order is not yet started)
tableB
taskid + orderid + task + status
1 | 1 | 1 | UPDATED
2 | 1 | 1 | UPDATED
3 | 1 | 1 | COMPLETED
4 | 2 | 2 | SAVED
5 | 3 | 3 | COMPLETED
My problem here is that when I count base on status (# tableB) my query results both the UPDATED which has the same orderid.
This is my sample query that same with the one I'm working.
SELECT t.name
COUNT(CASE WHEN tb.task = 1 AND tb.status <> 'COMPLETED' THEN tb.status ELSE NULL END) inprogress,
COUNT(CASE WHEN tb.task = 1 AND tb.status = 'COMPLETED' THEN tb.status ELSE NULL END) completed
FROM tableA ta
LEFT JOIN tableB tb
ON tb.orderid = ta.orderid
LEFT JOIN table t
ON t.jobid = ta.jobid
GROUP BY t.jobid;
My results something like
name + inprogress + completed
jobA | 2 | 1
The inprogress results must only be 1 because it has the same orderid. The reason why it has two UPDATED because this table is HISTORICAL. I don't know how can get the distinct orderid in tableB so it will only results to 1.
The main point here is that I can count the total orders which status is in progress, completed and not started per job.
I hope my question is clear. If you have other way, please let me know. Thanks
Can't you use a Count distinct? Here's a link, see nearer the bottom of the page, it will only the unique field you specify: w3schools.com/sql/sql_func_count.asp
SELECT t.name
COUNT(DISTINCT tb.orderid CASE WHEN tb.task = 1 AND tb.status 'COMPLETED' THEN tb.status
ELSE NULL END) inprogress,
COUNT(DISTINCT tb.orderid CASE WHEN tb.task = 1 AND tb.status = 'COMPLETED' THEN tb.status
ELSE NULL END) completed