【问题标题】:Select records in table A with *only* certain corresponding records in table B选择表 A 中的记录,其中*仅*表 B 中的某些相应记录
【发布时间】:2015-08-18 22:27:33
【问题描述】:

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

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'
)

但是,这感觉有点笨拙和程序化。有没有更优雅的解决方案,可能涉及自联接?

【问题讨论】:

    标签: sql sqlite subquery self-join


    【解决方案1】:

    如果你想使用自连接:

    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
    

    【讨论】:

    • 这似乎也是最快的解决方案。谢谢!
    【解决方案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 输入。

    【讨论】:

      【解决方案3】:

      我倾向于对这些类型的查询使用否定的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
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-09
        • 1970-01-01
        • 2016-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多