选择表A中的记录,其中*仅*表B中的某些相应记录

时间:2015-08-18 22:27:33

标签: sql sqlite subquery self-join

例如,假设您有一个文件表和一个传输操作的记录表。

CREATE TABLE files
(
  id INTEGER PRIMARY KEY
  -- various other columns
);

CREATE TABLE transfers
(
  id      INTEGER PRIMARY KEY,
  file_id INTEGER,
  status  TEXT NOT NULL,
  -- various other columns
  FOREIGN KEY (file_id) REFERENCES files (id)
)

传输操作可以有各种状态 - 'succeeded''failed''in progress'等。一个文件可以有多个传输操作 - 特别是,如果传输失败,另一个该文件的转移可能会在稍后安排。

现在,我们想要查找失败传输的所有文件 - 当前没有正在进行的传输,以后没有成功传输。

到目前为止,我有以下解决方案的子选择:

SELECT files.*
FROM files
WHERE files.id IN (
  SELECT DISTINCT file_id
  FROM transfers
  WHERE transfers.status == 'failed'
) AND files.id NOT IN (
  SELECT DISTINCT file_id
  FROM transfers
  WHERE transfers.status <> 'failed'
)

然而,这感觉有点笨拙和程序性。是否有更优雅的解决方案,可能涉及自连接?

3 个答案:

答案 0 :(得分:3)

如果您想使用自我加入:

fillOne()

答案 1 :(得分:2)

带有having子句的聚合怎么样?

select t.file_id
from transfers t
group by t.file_id
having sum(case when status <> 'failed' then 1 else 0 end) = 0;

如果有files所需的其他信息,您可以join进入。

答案 2 :(得分:1)

我倾向于对这些类型的查询使用否定的exists,因为它们倾向于使用适当的索引执行正常,并且在我看来反映了意图(或语义)或查询。

SELECT file_id
FROM transfers t
WHERE t.status = 'failed'
  AND NOT EXISTS (
    SELECT 1 
    FROM transfers
    WHERE status <> 'failed'
      AND file_id = t.file_id
);