Aggregate functions to specific values in a Group By query - sql

I have this data (for example):
id col1 col2
--------------------------------
5614 (null) Y
5614 Y (null)
5614 Y (null)
I want to obtain a single line where it tells me if the fields has some value Y.
id col1 col2
5614 Y Y
If no value Y present, then it should be N.
My actual query do that, but I think it should be a shorter way:
SELECT op.id,
CASE WHEN (SUM(CASE WHEN col1 = 'S' THEN 1 ELSE 0 END)) > 0 THEN 'S' ELSE 'N' END AS col1,
CASE WHEN (SUM(CASE WHEN col2 = 'S' THEN 1 ELSE 0 END)) > 0 THEN 'S' ELSE 'N' END AS col2
FROM OPERATOR op LEFT JOIN TRAM_OP tr ON op.id = tr.id AND tr.id2 = 20
WHERE op.id = 5614 GROUP BY op.id
As you can see I have two tables and I need to join them to match the id2 key.

One way is to use a shorthand that eliminates the need for some of the case statements:
SELECT op.id,
(CASE WHEN SUM(col1 = 'S') > 0 THEN 'S' ELSE 'N' END) AS col1,
(CASE WHEN SUM(col2 = 'S') > 0 THEN 'S' ELSE 'N' END) AS col2
FROM OPERATOR op LEFT JOIN
TRAM_OP tr
ON op.id = tr.id AND tr.id2 = 20
WHERE op.id = 5614
GROUP BY op.id;
You could also take advantage of the fact the 'S' > 'N':
SELECT op.id, MAX(col1) AS col1, MAX(col2) AS col2
FROM OPERATOR op LEFT JOIN
TRAM_OP tr
ON op.id = tr.id AND tr.id2 = 20
WHERE op.id = 5614
GROUP BY op.id;
However, this version might be confusing to someone else reading the code.

If Y is the only possible value, then with a simple max, you get either this value or NULL:
SELECT id, max(col1) AS col1, max(col2) AS col2
FROM ...
WHERE ...
GROUP BY id
You can change the NULL to 'N' with the ifnull function:
SELECT id,
ifnull(max(col1), 'N') AS col1,
ifnull(max(col2), 'N') AS col2
FROM ...
WHERE ...
GROUP BY id

Select ID,
case when Col1 > 0 then 'Y' else 'N' end 'COL1',
case when Col2 > 0 then 'Y' else 'N' end 'COL2'
from
(
Select id,SUM(case when Col1 = 'y' then 1 else 0 end)'COL1', SUM(
case when Col2 = 'y' then 1 else 0 end
)'COL2'
from #temp
group by id
) t

Related

Sql query to create following tables

use the below table 1 to generate table 2
Table 1
Col1 A B C
------------------
N1 1 0 0
N2 0 1 0
N3 1 0 0
Table 2
output
new_col
-------
N1 A
N2 B
N3 A
Also how to use Table 2 to generate table 1 above
Following SQL query can be help to get requested output:
SELECT Col1,IF(A=1,'A',IF(B=1,'B','C')) AS result FROM `table_name`;
You can use conditinal with CONCAT() Function :
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END)
FROM table1
provided you're on a DBMS with brand name such as MySQL, PostGRES, SQL Server. As an example, Oracle DB won't allow using more than two arguments for CONCAT() Function.
In order to create table2, use for most of the DBMS :
CREATE TABLE table2 AS
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
FROM table1
except for SQL Server in which prefer using :
SELECT CONCAT(col1,' ',
CASE WHEN A = 1 THEN 'A' ELSE '' END,
CASE WHEN B = 1 THEN 'B' ELSE '' END,
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
INTO table2
FROM table1
In order to implement a reverse engineering(go back to original table), you need to consider the dialectics for each seperate database to handle string values. Assume you're using MySQL DB, then consider using :
CREATE TABLE table3 AS
SELECT SUBSTRING(new_col,1,instr(new_col,' ')-1) AS col1,
CASE WHEN instr(new_col,'A') > 0 THEN 1 ELSE 0 END AS A,
CASE WHEN instr(new_col,'B') > 0 THEN 1 ELSE 0 END AS B,
CASE WHEN instr(new_col,'C') > 0 THEN 1 ELSE 0 END AS C
FROM table2
where I used a different table name (table3), since table1 already exists.
Demo
Btw, if Oracle DB is the case, then use :
SELECT CONCAT(CONCAT(col1,' '),
CASE WHEN A = 1 THEN 'A' ELSE '' END||
CASE WHEN B = 1 THEN 'B' ELSE '' END||
CASE WHEN C = 1 THEN 'C' ELSE '' END) AS new_col
FROM table1
You can use one case statement. This works in Oracle.
SELECT col1
|| CASE
WHEN A = 1
THEN 'A'
WHEN B = 1
THEN 'B'
WHEN C = 1
THEN 'C'
END
NEW_COL
FROM table1
It is unclear what you want when there are multiple "1"s in a row. This is a simple solution:
select id, A from t where A = 1
union all
select id, B from t where B = 1
union all
select id, C from t where C = 1;
In databases that support lateral joins, I would recommend:
select t.id, v.which
from t cross join lateral
(values ('A', t.A), ('B', B), ('C', C)
) v(which, val)
where val = 1;

case statement to find one value

I'm trying to show one row per id but it is returning three.
If the id has a 'y' then it should show a 'y'.
If it shows a 'y' and 'r' it should be 'y'.
If it has 'y', 'r', 'n' it should be 'y'.
If it is just id and 'r' it should be 'r' and id and just 'n' then 'n'.
I can't seem to get it to work using a case statement. Any ideas? Thanks.
I've tried this:
,CASE WHEN result = 'Y' THEN 'Y'
WHEN result = 'Y' AND result = 'R') THEN 'Y'
WHEN result = 'R' THEN 'R'
ELSE 'N' END AS CARE_PLAN
What it is returning:
ID result
3434 'y'
3434 'r'
3434 'n'
You can use Listagg function,
Writing a subquery and DISTINCT then use Listagg function.
SELECT id, Listagg (result, ', ')
within GROUP (ORDER BY result) as CARE_PLAN
FROM (SELECT DISTINCT id,
( CASE
WHEN result = 'Y' THEN 'Y'
WHEN result = 'Y'
AND result = 'R' THEN 'Y'
WHEN result = 'R' THEN 'R'
ELSE 'N'
END ) AS result
FROM t) T
GROUP BY id
sqlfiddle:http://sqlfiddle.com/#!4/02cd5/2
[Results]:
| ID | CARE_PLAN |
|------|-----------|
| 1234 | N, R, Y |
It shall be proper to use ASCII and CHR functions for your case instead of using CASE .. WHEN, as in the following :
SELECT ID, CHR(MAX(ASCII(result))) AS CARE_PLAN
FROM TAB
GROUP BY ID
ORDER BY ID;
SQL Fiddle Demo
You would seem to want aggregation with some conditional logic:
select id,
(case when sum(case when result = 'y' then 1 else 0 end) > 0 then 'y'
when sum(case when result = 'r' then 1 else 0 end) > 0 then 'r'
when min(result) = max(result) and min(result) = 'n' then 'n'
else '?'
end) as new_result
from t
group by id;
If there are only those three values, then perhaps this simplified logic works:
select id, max(result) as new_result
from t
group by id;

Output of Multiple Select Statement In Single Row

I have multiple query which is providing count based on different where condition.
Will it be possible to bring all result in single Rows.
for eg:
Query1:
SELECT COUNT(COL25) ASSURED, FROM TAB1 WHERE COL1= 'ALPHA' AND COL2='ROLE'
Query2:
SELECT COUNT(COL25) RELEASE FROM TAB1 WHERE COL3 in('BEETA','X','Y') AND COLSTATUS='ABC'
The result for 1st query is ASSURED = 100
and 2nd Query is RELEASE = 5000
i am trying to display output as
ASSURED | RELEASE
100 | 5000
Use conditional aggregation:
SELECT SUM(CASE WHEN COL1 = 'ALPHA' AND COL2 = 'ROLE' THEN 1 ELSE 0 END) as ASSURED,
SUM(CASE WHEN COL3 = 'BEETA' AND COLSTATUS = 'ABC' THEN 1 ELSE 0 END) as RELEASE
FROM TAB1;
EDIT:
If you actually need to count non-NULL values, you can be explicit (my preference):
SELECT SUM(CASE WHEN COL1 = 'ALPHA' AND COL2 = 'ROLE' AND col25 IS NOT NULL THEN 1 ELSE 0 END) as ASSURED,
SUM(CASE WHEN COL3 = 'BEETA' AND COLSTATUS = 'ABC' AND col25 IS NOT NULL THEN 1 ELSE 0 END) as RELEASE
FROM TAB1;
Or be a bit more implicit:
SELECT COUNT(CASE WHEN COL1 = 'ALPHA' AND COL2 = 'ROLE' THEN col25 END) as ASSURED,
COUNT(CASE WHEN COL3 = 'BEETA' AND COLSTATUS = 'ABC' THEN col25 END) as RELEASE
FROM TAB1;
You can also use joins, but #Gordon Linoff answer is cleaner and way shorter than this.
SELECT first.ASSURED, second.RELEASE
FROM
(SELECT
COUNT(COL25) ASSURED
FROM TAB1
WHERE COL1= 'ALPHA' AND COL2='ROLE') AS first
INNER JOIN (SELECT
COUNT(COL25) RELEASE
FROM TAB1
WHERE COL3 in('BEETA','X','Y')
AND COLSTATUS='ABC') AS second
ON 1=1

counting records on the same table with different values possibly none sql server 2008

I have a inventory table with a condition i.e. new, used, other, and i am query a small set of this data, and there is a possibility that all the record set contains only 1 or all the conditions. I tried using a case statement, but if one of the conditions isn't found nothing for that condition returned, and I need it to return 0
This is what I've tried so far:
select(
case
when new_used = 'N' then 'new'
when new_used = 'U' then 'used'
when new_used = 'O' then 'other'
end
)as conditions,
count(*) as count
from myDB
where something = something
group by(
case
when New_Used = 'N' then 'new'
when New_Used = 'U' then 'used'
when New_Used = 'O' then 'other'
end
)
This returns the data like:
conditions | count
------------------
new 10
used 45
I am trying to get the data to return like the following:
conditions | count
------------------
new | 10
used | 45
other | 0
Thanks in advance
;WITH constants(letter,word) AS
(
SELECT l,w FROM (VALUES('N','new'),('U','used'),('O','other')) AS x(l,w)
)
SELECT
conditions = c.word,
[count] = COUNT(x.new_used)
FROM constants AS c
LEFT OUTER JOIN dbo.myDB AS x
ON c.letter = x.new_used
AND something = something
GROUP BY c.word;
try this -
DECLARE #t TABLE (new_used CHAR(1))
INSERT INTO #t (new_used)
SELECT t = 'N'
UNION ALL
SELECT 'N'
UNION ALL
SELECT 'U'
SELECT conditions, ISNULL(r.cnt, 0) AS [count]
FROM (
VALUES('U', 'used'), ('N', 'new'), ('O', 'other')
) t(c, conditions)
LEFT JOIN (
SELECT new_used, COUNT(1) AS cnt
FROM #t
--WHERE something = something
GROUP BY new_used
) r ON r.new_used = t.c
in output -
new 2
used 1
other 0
You can do it as a cross-tab:
select
sum(case when new_used = 'N' then 1 else 0 end) as N,
sum(case when new_used = 'U' then 1 else 0 end) as U,
sum(case when new_used = 'O' then 1 else 0 end) as Other
from myDB
where something = something

Find records with column containing specific values

I think my question really boils down do doing a sql IN on multiple values.
Here's a SQL Fiddle of what I have so far.
So long story short, I have Cases that have multiple Types.
I need to filter Cases containing certain Types
Say I have 6 rows (col1,col2)... (1,2),(1,3)(1,4),(2,3),(2,4),(2,5)
How do I select only Cases that have 2, AND 3 AND 4 in col2?
2,3,4 is just a use case. It could be just about any combination (the SQL Fiddle has a couple tables that determine this).
Try:
select [CaseId]
from CaseTypes
where [TypeID] in (2,3,4)
group by [CaseId]
having count(distinct [TypeID]) = 3
(SQLFiddle here)
Couple of things you might try:
Using Derived Tables:
SELECT a.col1
FROM (SELECT col1 FROM Cases WHERE col2 = 2) a
INNER JOIN (SELECT col1 FROM Cases WHERE col2 = 3) b ON a.col1 = b.col1
INNER JOIN (SELECT col1 FROM Cases WHERE col2 = 4) c ON a.col1 = c.col1
Using Aggregation:
SELECT col1
FROM Cases
GROUP BY col1
HAVING
SUM(CASE col2 WHEN 2 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE col2 WHEN 3 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE col2 WHEN 4 THEN 1 ELSE 0 END) > 0
is this a bit closer?
SELECT * from CaseTypes CT
INNER JOIN TypeBillable TB ON CT.TypeId = TB.TypeId
where CT.CaseId in
(
select CaseID from CaseTypes
PIVOT (count (TypeId) for TypeId in ([2],[3],[4])) as x
where [2] > 0 and [3] > 0 and [4] > 0
)