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;
Related
I'm pretty new to SQL and am trying to figure out if there's a way to aggregate the date into new column. For instance, below is a sample set of date. I want to take all the type '2' and create new columns
Mem Balance Type New
1 2500 2 0
2 722 66 1
3 9422 1 0
4 122 2 1
5 788 66 1
So instead of having it like above, it would be like
Mem Type2Balance Type66Balance Type2New Type66New
1 2622 0 1 0
2 0 1510 0 2
Is there a way to do this in SQL? I thought maybe using IF statements within a case statement? I'm not asking for it to be done for me, more of looking for specifics that I can read about to make this happen. Thank you!
It seems like you want:
select
case when type = 2 then sum(balance) else 0 end type2balance,
case when type = 66 then sum(balance) else 0 end type66balance,
case when type = 2 then sum(new) else 0 end type2new,
case when type = 66 then sum(new) else 0 end type66new
from mytable
where type in (2, 66)
group by type
I am not sure what logic you want for column Mem in the resulset. It that's just a row number, then:
select
row_number() over(order by type) mem,
case when type = 2 then sum(balance) else 0 end type2balance,
case when type = 66 then sum(balance) else 0 end type66balance,
case when type = 2 then sum(new) else 0 end type2new,
case when type = 66 then sum(new) else 0 end type66new
from mytable
where type in (2, 66)
group by type
We could put the conditional expression on type inside the aggregate function, but it does not really make sense since you are grouping by type already. In that case, that would be:
select
row_number() over(order by type) mem,
sum(case when type = 2 then balance else 0 end) type2balance,
sum(case when type = 66 then balance else 0 end) type66balance,
sum(case when type = 2 then new else 0 end) type2new,
sum(case when type = 66 then new else 0 end) type66new
from mytable
where type in (2, 66)
group by type
With conditional aggregation:
select min(mem) mem,
sum(case when type = 2 then balance else 0 end) Type2Balance,
sum(case when type = 66 then balance else 0 end) Type66Balance,
sum(case when type = 2 then new else 0 end) Type2New,
sum(case when type = 66 then new else 0 end) Type66New
from tablename
where type in (2, 66)
group by type
See the demo.
Results:
| mem | Type2Balance | Type66Balance | Type2New | Type66New |
| --- | ------------ | ------------- | -------- | --------- |
| 1 | 2622 | 0 | 1 | 0 |
| 2 | 0 | 1510 | 0 | 2 |
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
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
For the following Table, is it possible, to create an SQL Statement to create a data Matrix or view?
Table:
TeamA|TeamB|Won|Lost
--------------------
A | B | 5 | 3
A | C | 2 | 4
A | D | 9 | 1
B | E | 5 | 5
C | A | 2 | 4
Result-Matrix:
| A | B | C | D | E
----------------------------
A | 0 | 2 | -2 | 8 | 0
B | 0 | 0 | 0 | 0 | 0
C | -2 | 0 | 0 | 0 | 0
There are two ways that you can pivot data in MySQL. If you know the values ahead of time (teams) then you will hard-code the values or you can use a prepared statement to generate dynamic sql.
A static version would be:
select TeamA,
max(case when TeamB = 'A' then won - lost else 0 end) as A,
max(case when TeamB = 'B' then won - lost else 0 end) as B,
max(case when TeamB = 'C' then won - lost else 0 end) as C,
max(case when TeamB = 'D' then won - lost else 0 end) as D,
max(case when TeamB = 'E' then won - lost else 0 end) as E
from yourtable
group by TeamA;
See SQL Fiddle with Demo
If you want to use a dynamic version with a prepared statement, the code would be:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN TeamB = ''',
TeamB,
''' THEN won - lost else 0 END) AS `',
TeamB, '`'
)
) INTO #sql
from
(
select *
from yourtable
order by teamb
) x;
SET #sql
= CONCAT('SELECT TeamA, ', #sql, '
from yourtable
group by TeamA');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo.
Edit #1, after thinking about this I would actually do this a slight bit different. I would generate a true matrix os the data where the teams appeared in both the row and the column. To do this you would first use a UNION ALL query to get all teams in two columns:
select teama Team1, teamb Team2,
won-lost Total
from yourtable
union all
select teamb, teama,
won-lost
from yourtable
See SQL Fiddle with Demo. Once that is done, then you would pivot the data:
select Team1,
coalesce(max(case when Team2 = 'A' then Total end), 0) as A,
coalesce(max(case when Team2 = 'B' then Total end), 0) as B,
coalesce(max(case when Team2 = 'C' then Total end), 0) as C,
coalesce(max(case when Team2 = 'D' then Total end), 0) as D,
coalesce(max(case when Team2 = 'E' then Total end), 0) as E
from
(
select teama Team1, teamb Team2,
won-lost Total
from yourtable
union all
select teamb, teama,
won-lost
from yourtable
) src
group by Team1;
See SQL Fiddle with Demo. Which gives a more detailed result of:
| TEAM1 | A | B | C | D | E |
-------------------------------
| A | 0 | 2 | -2 | 8 | 0 |
| B | 2 | 0 | 0 | 0 | 0 |
| C | -2 | 0 | 0 | 0 | 0 |
| D | 8 | 0 | 0 | 0 | 0 |
| E | 0 | 0 | 0 | 0 | 0 |
You cannot create a SQL statement or view that has a variable number of columns. In standard SQL, you can pivot the data by doing something like:
select TeamA,
max(case when TeamB = 'A' then won - lost end) as A,
max(case when TeamB = 'B' then won - lost end) as B,
max(case when TeamB = 'C' then won - lost end) as C,
max(case when TeamB = 'D' then won - lost end) as D,
max(case when TeamB = 'E' then won - lost end) as E
from t
group by TeamA
order by 1
Some databases support a pivot statement.
To do this generically, you would have to create a SQL statement as a string, and then execute it (often called dynamic SQL). Such a statement could be produced by SQL, by a stored procedure, in Excel, or some other programming tool. It then would need to be executed.
Let me repeat: any given SQL statement has a pre-defined set of columns. You cannot vary the number of columns.
idI have a table like this
|----|-----------|--------|
| ID | Ethnicity | Gender |
| 1 | 2 | 1 |
| 2 | 3 | 1 |
| 3 | 4 | 2 |
|----|-----------|--------|
etc ....
And I'm trying to get back a set of results that show me ethnicities group by male(1) and female(2)
So the result row would in this example would be:
Ethnicity Male Female
2 1 0
3 1 0
4 0 1
So far I'm close with to what I want with:
SELECT ethnicity,
(SELECT
count(id)
FROM
table_name
WHERE
gender = '2' ) as female,
(SELECT
count(id)
FROM
table_name
WHERE
gender = '1') as male
FROM table_name
GROUP BY ethnicity
Which gives me:
Ethnicity Male Female
2 2 1
3 2 1
4 2 1
But need the count(id) to only be a count of the adno of that ethnicity row if that makes sense.
Try this instead:
SELECT
ethnicity,
SUM(CASE WHEN gender = 1 THEN 1 ELSE 0 END) AS female,
SUM(CASE WHEN gender = 2 THEN 1 ELSE 0 END) AS Male
FROM students
GROUP BY ethnicity;
The above should work in virtually any SQL product, not just in MySQL. If you like, however, you can also use this version, which employs MySQL's implicit conversion of booleans to ints (true -> 1, false -> 0):
SELECT
ethnicity,
SUM(gender = 1) AS female,
SUM(gender = 2) AS Male
FROM students
GROUP BY ethnicity;
SELECT
ethnicity,
CASE WHEN gender = 1 THEN 1 ELSE 0 END AS Male,
CASE WHEN gender = 2 THEN 1 ELSE 0 END AS Female
FROM students