I have a column with can be any of three possible elements, call them x,y,z. The column is not allowed to be only z.
I can imagine this in set theory where S = {x,y,z}, and I require all subsets of S except the set {z}.
How would I write a SQL statement that let's the column be any subset of x,y,z except z alone?
For example:
| ID | Value |
|---|---|
| 1 | x |
| 1 | y |
| 1 | z |
| 2 | x |
| 2 | z |
| 3 | z |
| 3 | z |
Desired output:
| ID | Value |
|---|---|
| 1 | x |
| 1 | y |
| 1 | z |
| 2 | x |
| 2 | z |
CodePudding user response:
You may try with count window function as the following:
Select ID, Value
From
(
Select ID, Value,
Count(Case When Value = 'z' Then 1 End) Over (Partition By ID) As z_cnt,
Count(*) Over (Partition By ID) As all_cnt
From table_name
) T
Where z_cnt <> all_cnt
See demo.
CodePudding user response:
You can use an exists semi-join:
select *
from t
where not exists (
select *
from t t2
where t2.Id = t.Id and t.Value = 'Z'
group by id
having Count(distinct value) = 1
);
CodePudding user response:
You can use EXCEPT with your conditions
SELECT [ID], [Value] FROM tab
EXCEPT
SELECT [ID], [Value] FROm tab t1 WHERE [Value] = 'z' AND (SELECT COUNT(*) FROm tab WHERE [ID] = t1.[ID]) = 1
| ID | Value |
|---|---|
| 1 | x |
| 1 | y |
| 1 | z |
| 2 | x |
| 2 | z |
If the data are not unique you can use NOT IN instead of
CREATE TABLE tab
([ID] int, [Value] varchar(1))
;
INSERT INTO tab
([ID], [Value])
VALUES
(1, 'x'),
(1, 'y'),
(1, 'z'),
(2, 'x'),
(2, 'z'),
(3, 'z'),
(3, 'z'),
(3, 'z'),
(4, 'x'),
(4, 'x'),
(4, 'x'),
(5, 'y'),
(5, 'y'),
(5, 'y')
;
14 rows affected
SELECT [ID], [Value] FROM tab
WHERE [ID] NOt IN (
SELECT [ID] FROm tab t1 WHERE [Value] = 'z'
AND (SELECT COUNT(DISTINCT [Value]) FROm tab WHERE [ID] = t1.[ID]) = 1)
| ID | Value |
|---|---|
| 1 | x |
| 1 | y |
| 1 | z |
| 2 | x |
| 2 | z |
| 4 | x |
| 4 | x |
| 4 | x |
| 5 | y |
| 5 | y |
| 5 | y |
