How to query within the same table - sql

I need to query a single table based on the contents of the same table
currently i have used in within and, which is taking a lot of time to query & i know its not the smartest way
PID CID Status
1 1 1
1 2 0
1 3 1
1 4 1
1 5 1
2 1 1
2 2 1
2 3 1
2 4 0
2 5 0
from the above table i need results which satisfy the following combination
Select PID from Tablename where
(CID in (1) AND status 1)
AND
(CID in (2,3) AND status = 1)
AND
(CID in (4) AND status = 1)
AND
(CID in (5) AND status = 1)
So as per above requirement, i should get only PID 1

This should get all the PIDs which exist in all the select statements:
SELECT PID FROM TableName WHERE CID = 1 AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID IN (2, 3) AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID = 4 AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID = 5 AND Status = 1

You seem to want:
Select PID
from Tablename
where status = 1
group by PID
having sum(case when CID in (1) then 1 else 0 end) > 0 and
sum(case when CID in (2, 3) then 1 else 0 end) > 0 and
sum(case when CID in (4) then 1 else 0 end) > 0 and
sum(case when CID in (5) then 1 else 0 end) > 0;
Your query only tests values within a single row. The where condition can never evaluate to true.
Here is a db<>fiddle, showing that this returns PID = 1 for the data in your example.

Related

Select table adding columns with data depending on duplicates in other column

Imagine this data.
Id
Type
1
A
1
B
1
B
2
A
3
B
I want to select table and ad two columns turning it to this. How can i do it? (In teradata)
Id
Type
Id with both A+B
Id with only A
1
A
1
0
1
B
1
0
1
B
1
0
2
A
0
1
3
B
0
0
I'm not familiar with teradata but in standard SQL next query should be working:
SELECT
T.*,
CASE WHEN Cnt = 2 THEN 1 ELSE 0 END AS BOTH_TYPES_PRESENT,
CASE WHEN Cnt = 1 AND Type = 'A' THEN 1 ELSE 0 END AS ONLY_A_PRESENT
FROM T
LEFT JOIN (
SELECT Id, COUNT(DISTINCT Type) Cnt FROM T WHERE Type IN ('A', 'B') GROUP BY Id
) CNT ON T.Id = CNT.Id;
SQL online editor

Adding a dummy identifier to data that varies by position and value

I am working on a project in SQL Server with diagnosis codes and a patient can have up to 4 codes but not necessarily more than 1 and a patient cannot repeat a code more than once. However, codes can occur in any order. My goal is to be able to count how many times a Diagnosis code appears in total, as well as how often it appears in a set position.
My data currently resembles the following:
PtKey
Order #
Order Date
Diagnosis1
Diagnosis2
Diagnosis3
Diagnosis 4
345
1527
7/12/20
J44.9
R26.2
NULL
NULL
367
1679
7/12/20
R26.2
H27.2
G47.34
NULL
325
1700
7/12/20
G47.34
NULL
NULL
NULL
327
1710
7/12/20
I26.2
J44.9
G47.34
NULL
I would think the best approach would be to create a dummy column here that would match up the diagnosis by position. For example, Diagnosis 1 with A, and Diagnosis 2 with B, etc.
My current plan is to rollup the diagnosis using an unpivot:
UNPIVOT ( Diag for ColumnALL IN (Diagnosis1, Diagnosis2, Diagnosis3, Diagnosis4)) as unpvt
However, this still doesn’t provide a way to count the diagnoses by position on a sales order.
I want it to look like this:
Diagnosis
Total Count
Diag1 Count
Diag2 Count
Diag3 Count
Diag4 Count
J44.9
2
1
1
0
0
R26.2
1
1
0
0
0
H27.2
1
0
1
0
0
I26.2
1
1
0
0
0
G47.34
3
1
0
2
0
You can unpivot using apply and aggregate:
select v.diagnosis, count(*) as cnt,
sum(case when pos = 1 then 1 else 0 end) as pos_1,
sum(case when pos = 2 then 1 else 0 end) as pos_2,
sum(case when pos = 3 then 1 else 0 end) as pos_3,
sum(case when pos = 4 then 1 else 0 end) as pos_4
from data d cross apply
(values (diagnosis1, 1),
(diagnosis2, 2),
(diagnosis3, 3),
(diagnosis4, 4)
) v(diagnosis, pos)
where diagnosis is not null;
Another way is to use UNPIVOT to transform the columns into groupable entities:
SELECT Diagnosis, [Total Count] = COUNT(*),
[Diag1 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis1' THEN 1 ELSE 0 END),
[Diag2 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis2' THEN 1 ELSE 0 END),
[Diag3 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis3' THEN 1 ELSE 0 END),
[Diag4 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis4' THEN 1 ELSE 0 END)
FROM
(
SELECT * FROM #x UNPIVOT (Diagnosis FOR DiagGroup IN
([Diagnosis1],[Diagnosis2],[Diagnosis3],[Diagnosis4])) up
) AS x GROUP BY Diagnosis;
Example db<>fiddle
You can also manually unpivot via UNION before doing the conditional aggregation:
SELECT Diagnosis, COUNT(*) As Total Count
, SUM(CASE WHEN Position = 1 THEN 1 ELSE 0 END) As [Diag1 Count]
, SUM(CASE WHEN Position = 2 THEN 1 ELSE 0 END) As [Diag2 Count]
, SUM(CASE WHEN Position = 3 THEN 1 ELSE 0 END) As [Diag3 Count]
, SUM(CASE WHEN Position = 4 THEN 1 ELSE 0 END) As [Diag4 Count]
FROM
(
SELECT PtKey, Diagnosis1 As Diagnosis, 1 As Position
FROM [MyTable]
UNION ALL
SELECT PtKey, Diagnosis2 As Diagnosis, 2 As Position
FROM [MyTable]
WHERE Diagnosis2 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis3 As Diagnosis, 3 As Position
FROM [MyTable]
WHERE Diagnosis3 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis4 As Diagnosis, 4 As Position
FROM [MyTable]
WHERE Diagnosis4 IS NOT NULL
) d
GROUP BY Diagnosis
Borrowing Aaron's fiddle, to avoid needing to rebuild the schema from scratch, and we get this:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d1f7f525e175f0f066dd1749c49cc46d

how to get the count of data based on status id in sql

i have following table
id statusid
100 1
100 2
100 3
101 1
101 3
i am getting the result like following
id data1 data2 data3
100 1 1 1
101 1 0 1
but i want the result like following
id data1 data2+data3
100 1 2
101 1 1
i am using the following query:
select id, SUM(CASE WHEN statusid=1 THEN 1 ELSE 0 END) AS data1,
SUM(CASE WHEN statusid=2 THEN 1 ELSE 0 END) AS data2,
SUM(CASE WHEN statusid=3 THEN 1 ELSE 0 END) AS data3
from employee
group by id
any help.
thank you.
Sudha.
You can count statuses 2 and 3 together like so:
select id,
sum(case when statusid = 1 then 1 else 0 end) as data1,
sum(case when statusid in (2, 3) then 1 else 0 end) as data2_3
from employee
group by id
You may use PIVOT clause to get the required result.
Use DECODE to map the status so that the 2 and 3 produce the same value
with tab2 as (select
id, decode(status_id,3,2,status_id) status_id2
from tab)
select * from tab2
PIVOT (count(*) "CNT" for status_id2 in
(1 as "DATA_1",
2 as "DATA_2_3")
)
ID DATA_1_CNT DATA_2_3_CNT
---------- ---------- ------------
100 1 2
101 1 1

SQL to find IDs which never had a column value

Below is my data:
ID
request_type
1
3
1
2
1
1
1
4
1
5
2
3
2
2
3
4
3
2
I need a query to fetch IDs that never had a request type of 1 (e.g. 2,3 from the previous table).
With conditional aggregation:
select id
from tablename
group by id
having count(case when request_type = 1 then 1 end) = 0
SELECT DISTINCT `ID`
FROM `my_table`
WHERE `ID` NOT IN (
SELECT DISTINCT `ID`
FROM `my_table`
WHERE `request_type` = 1
)
If 1 is the lowest possible value:
select ID
from tab
group by ID
having min (request_type) > 1
Or more generic:
select ID
from tab
group by ID
having max(case when request_type = 1 then 1 else 0 end) = 0

SQL - Select items where value equals multiple values

Have a very hard time wording this question, but below is a table to illustrate my problem.
Id itemID categoryID
1 5 10
2 5 16
3 6 10
4 2 10
If I have a table setup like this, and I want to select "itemID" where categoryID equals 10 AND 16, the result should be itemID 5. A bit more context would be the user has a list of checkboxes that are the categoryID's, and if they select just categoryID 10, then itemID 5, 2 and 6 would appear. If they also select categoryID 16, then only itemID 5 would appear since it has category 10 and 16, where itemID 2 only has category 10.
This is an example of a "set-within-sets" subquery. I think the most general way to solve these is using aggregation and a having clause:
select itemID
from t
group by itemId
having sum(case when categoryID = 10 then 1 else 0 end) > 0 and
sum(case when categoryID = 16 then 1 else 0 end) > 0;
Each condition in the having clause is counting the number of rows that match one category. You can easily see how this would generalize for more categories, or to exclude a category. For instance, if you wants 10 and 16 but not 22:
select itemID
from t
group by itemId
having sum(case when categoryID = 10 then 1 else 0 end) > 0 and
sum(case when categoryID = 16 then 1 else 0 end) > 0 and
sum(case when categoryID = 22 then 1 else 0 end) = 0;
Join the table to itself:
select t1.itemID
from mytable t1
join mytable t2 on t2.itemID = t1.itemID
where t1.categoryID = 10
and t2.categoryID = 16;