Select table A 中的记录与 table B 中*仅*某些对应的记录
Select records in table A with *only* certain corresponding records in table B
例如,假设您有 table 个文件和 table 个传输操作记录。
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'
)
但是,这感觉有点笨拙和程序化。是否有更优雅的解决方案,可能涉及自连接?
带有 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
加入。
如果您想使用自连接:
SELECT DISTINCT files.*
FROM
files INNER JOIN transfers t1
ON files.id = t1.file_id AND t1.status='failed'
LEFT JOIN transfers t2
ON file.id = t2.file_id AND t2.status<>'failed'
WHERE
t2.id IS NULL
我倾向于对这些类型的查询使用否定 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
);
例如,假设您有 table 个文件和 table 个传输操作记录。
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'
)
但是,这感觉有点笨拙和程序化。是否有更优雅的解决方案,可能涉及自连接?
带有 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
加入。
如果您想使用自连接:
SELECT DISTINCT files.*
FROM
files INNER JOIN transfers t1
ON files.id = t1.file_id AND t1.status='failed'
LEFT JOIN transfers t2
ON file.id = t2.file_id AND t2.status<>'failed'
WHERE
t2.id IS NULL
我倾向于对这些类型的查询使用否定 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
);