我希望能够在子表中返回不包含特定行的唯一ID列表。
我的表类似于:
Id Name
1 X
1 Y
1 Z
2 A
2 B
2 C
3 X
3 B
3 Z
我想写一个像
这样的SQL查询SELECT Id
FROM table t
WHERE UPPER(t.Name) IN ('X', 'Y', 'Z')
OR UPPER(t.Name) IN ('A', 'B', 'C')
GROUP BY t.Id
HAVING COUNT(DISTINCT UPPER(t.Name)) != 3
但这不起作用,因为我预计只有Id = 3才会被返回为无效。
这可以在单个SQL语句中使用吗?
此外,如果有任意数量的列表(X,Y,Z; A,B,C; P,Q,Z; ...)或混合列表长度(X),是否可以解决此问题,Y; A,B,C,D; L,M,N; ......)?
编辑:
为了澄清,每个id实际上都是指父表。所以这些是儿童记录。
在第一个示例中,父记录仅在包含至少3个子项时才有效。必须将3个孩子命名为(A,B和C)或(X,Y和Z)。父母即使包含所有6个孩子也有效。但是有4个名为A,B,X,Y的孩子无效(添加C或Z孩子会使其有效)。
到目前为止,戈登·林诺夫最接近。我需要再写一些测试。
当然这是一个人为的例子,在我的实现中,不同的规则集将要求我使用不同大小的不同列表(可能是混合的)。例如,我可能有一条规则,即只有父项有子(A和B)或(W,X,Y和Z)或(L,M,N和Z)的子项才有效。
谢谢,
答案 0 :(得分:2)
您希望查找不包含X,Y,Z或A,B,C的所有行。您可以使用aggregation和having子句执行此操作:
select id
from t
group by name
having not ((sum(case when Name = 'X' then 1 else 0 end) > 0 and
sum(case when Name = 'Y' then 1 else 0 end) > 0 and
sum(case when Name = 'Z' then 1 else 0 end) > 0
) or
(sum(case when Name = 'A' then 1 else 0 end) > 0 and
sum(case when Name = 'B' then 1 else 0 end) > 0 and
sum(case when Name = 'C' then 1 else 0 end) > 0
)
);
having
子句中的每个条件都计算与特定名称匹配的行数。当存在至少一个时,一行通过过滤器。 and
和or
的组合似乎符合您的要求。
请注意,具有A,B,C和D的id
将匹配。您的问题没有说明这是正确还是不正确。
答案 1 :(得分:1)
Oracle 11g R2架构设置:
CREATE TABLE tbl ( Id NUMBER(1), Name VARCHAR2(1) );
INSERT INTO tbl VALUES ( 1, 'X' );
INSERT INTO tbl VALUES ( 1, 'Y' );
INSERT INTO tbl VALUES ( 1, 'Z' );
INSERT INTO tbl VALUES ( 2, 'A' );
INSERT INTO tbl VALUES ( 2, 'B' );
INSERT INTO tbl VALUES ( 2, 'C' );
INSERT INTO tbl VALUES ( 3, 'X' );
INSERT INTO tbl VALUES ( 3, 'B' );
INSERT INTO tbl VALUES ( 3, 'Z' );
INSERT INTO tbl VALUES ( 4, 'F' );
INSERT INTO tbl VALUES ( 4, 'G' );
INSERT INTO tbl VALUES ( 4, 'H' );
CREATE TYPE VARCHAR2s_1_Table AS TABLE OF VARCHAR2(1);
查询1 :
WITH groups AS (
SELECT id,
CAST( COLLECT( Name ) AS VARCHAR2s_1_Table ) AS grp
FROM tbl
GROUP BY
id
)
SELECT id
FROM groups
WHERE ( grp MULTISET INTERSECT VARCHAR2s_1_Table( 'X', 'Y', 'Z') ) IS NOT EMPTY
AND ( grp MULTISET INTERSECT VARCHAR2s_1_Table( 'A', 'B', 'C') ) IS NOT EMPTY
<强> Results 强>:
| ID |
|----|
| 3 |
答案 2 :(得分:0)
CREATE TYPE string_table
AS TABLE OF VARCHAR2(1);
WITH grouped_names AS (
SELECT
id,
CAST(COLLECT(name) AS string_table) AS names_grp
FROM tbl
GROUP BY id
)
SELECT id
FROM grouped_names
WHERE string_table('A','B','C') NOT SUBMULTISET OF names_grp
AND string_table('X','Y','Z') NOT SUBMULTISET OF names_grp