2013-12-13 35 views
1

我希望能够返回不包含特定行的子表中的唯一ID列表。如何确定表中是否存在某些行的组合

我的表看起来类似于:

Id Name 
1 X 
1 Y 
1 Z 
2 A 
2 B 
2 C 
3 X 
3 B 
3 Z 

我想写像

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 

一个SQL查询但是,这并不工作,因为我希望只有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孩子会使其有效)。

到目前为止,Gordon Linoff是最接近的。我需要写更多的测试。

当然这是一个人为的例子,在我的实现中,不同的规则集将要求我使用不同大小的不同列表(可能混合)。例如,我可能有一个规则,只有当父项名为(A和B)或(W,X,Y和Z)或(L,M,N和Z)的子项时,父项才有效。

感谢,

+0

您使用的是什么RDBMS(Oracle,MySQL,SQL Server,...)? – peterm

+0

所有的ID都有3个不同的名字,你的有条件会把所有东西都去掉。 – Andrew

+0

我需要同时支持SQL Server和Oracle。 – SergioL

回答

2

你想找到不包含X的所有行,Y,Z或A,B,C可以采用聚集做到这一点,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子句中的每个条件都计算与特定名称匹配的行数。至少有一行通过过滤器。 andor的组合似乎满足您的要求。

请注意,具有A,B,C和D的id将匹配。您的问题没有说明这是正确还是错误。

+0

如果检查A,B,C,A,B,C,D将是有效的。 – SergioL

+0

我用来帮助动态创建这个语句的唯一改变是使用像(SUM(CASE WHEN UPPER(c.Name)IN('X','Y','Z')THEN 1 ELSE 0 END) = 3)替换个别呼叫。 – SergioL

+0

@SergioL。 。 。这很好,如果你知道行上没有重复的值。 –

1

SQL Fiddle

的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 | 
+0

'我认为WHERE VARCHAR2s_1_Table('X','Y','Z')不是grp的子流。 – SQB

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 
相关问题