关系部门-模仿“ ONLY IN”

时间:2019-01-14 15:53:06

标签: sql oracle relational-division

我试图用Oracle SQL编写一个查询,该查询带有两个参数,并在整个表中查找只有一个或两个都出现的所有实例,而不管搜索中有多少个实例。这是我要寻找的示例:

| ID  | FileType | COUNT(FileType) |
|-----|----------|-----------------|
| 1   | txt      | 1               |
| 1   | png      | 3               |
| 1   | jpg      | 2               |
====================================
| 2   | txt      | 0               |
| 2   | png      | 6               |
| 2   | jpg      | 0               |
====================================
| 3   | txt      | 0               |
| 3   | png      | 0               |
| 3   | jpg      | 5               |
====================================
| 4   | txt      | 0               |
| 4   | png      | 3               |
| 4   | jpg      | 1               |
====================================
| 5   | txt      | 5               |
| 5   | png      | 0               |
| 5   | jpg      | 3               |

我的目标是仅使用png的OR或jpg的ID作为所有ID,而忽略其余的ID,所以我只希望返回ID的2、3和4。

我试图在此处查找解决方案,但没有找到任何与我的情况相符的内容。 (最近的问题是:SQL select rows with only a certain value in them

我确实发现问题可以通过关系划分来解决,但是到目前为止我还没有任何经验。到目前为止,我的查询看起来像这样:

SELECT DISTINCT ID, FileType, COUNT(FileType)
FROM Table ta
WHERE (ta.FileType = 'jpg' or ta.FileType = 'png') and
NOT EXISTS
    (SELECT *
     FROM Table tb
     WHERE ta.FileType = tb.FileType and
     (tb.FileType != 'jpg' or tb.FileType != 'png'))
GROUP BY ID, FileType;

尝试此操作时,没有任何结果。有人对我在这里出错了有什么想法吗?

3 个答案:

答案 0 :(得分:2)

您可以使用集合运算符:

SELECT ID FROM tab WHERE FileType IN ('jpg', 'png')
MINUS
SELECT ID FROM tab WHERE FileType NOT IN ('jpg', 'png')

假设:文件类型不可为空。


处理NULL:

SELECT ID FROM tab WHERE FileType IN ('jpg', 'png')
MINUS
SELECT ID 
FROM (SELECT * FROM tab WHERE FileType IS NOT NULL) 
WHERE FileType NOT IN ('jpg', 'png')

答案 1 :(得分:1)

您很近。只要看看您有多少种不同的文件类型即可。这是您的ID:

SELECT ID
FROM Table ta
GROUP BY ID
HAVING count(distinct FileType) = 1 and max(ta.FileType) in ('jpg','png');

更新:情况4的鞋帮将失败。

这可以做到,但是很丑:

SELECT ID
FROM Table ta
GROUP BY ID
HAVING count(distinct FileType) <= 2 
   and max(ta.FileType) in ('jpg','png') 
   and min(ta.FileType) in ('jpg','png');

这很丑陋,因为您不能将其扩展为3个值。

答案 2 :(得分:0)

只需使用“助手”表:

WITH TypeCounts AS
(
  SELECT ID, FileType, COUNT(*) AS CNT
  FROM Table
  GROUP BY ID, FileType
)
SELECT *
FROM Table
LEFT JOIN TypeCounts txt ON txt.ID = Table.ID AND txt.FileType = 'txt'
LEFT JOIN TypeCounts jpg ON jpg.ID = Table.ID AND jpg.FileType = 'jpg'
LEFT JOIN TypeCounts png ON png.ID = Table.ID AND png.FileType = 'png'
WHERE COALESCE(txt.CNT,0) = 0 AND
    ( COALESCE(jpg.CNT,0) > 0 OR COALESCE(png.CNT,0) > 0)

此解决方案的优点是非常清楚什么是业务规则,因此更易于维护。