【问题标题】:How can I in SQL filter rows that only has an initial row per id?如何在 SQL 中过滤每个 id 只有一个初始行的行?
【发布时间】:2018-10-05 18:00:53
【问题描述】:

我有一个表,其 id 和 state 仅被写入,从未更新,我只想查询具有初始状态的 id,即只有第一行写入的 id 行,以便我可以处理它们用于状态更改。 如果处理正常,则会为这些 id 写入一个新状态,并且下次查询时,我不应该获得成功处理的 id 行。

示例:我有两行用于状态为“INITIAL”和“DONE”的 ID,另一行用于状态为“INITIAL”的第二个 ID。 当我查询时,我只想获得第二个 id。

我尝试过使用 group by,但由于我无法在不对其进行分组的情况下过滤状态,所以它没有按照我的预期工作。

我想出了这个查询,但这真的是如何解决的吗?

select id, state from states s1 where state = 'INITIAL' and not exists
(select 1 from states s2 where s2.state != 'INITIAL' and s2.id = s1.id);

顺便说一句,我正在使用 Postgres :)

我在这里发现了许多类似的问题,但不完全是这个,但是如果你知道的话,请指导我寻找另一个答案! :)

感谢您的帮助!

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    一个选项,也许是最有效的,使用NOT EXISTS 子句:

    SELECT id, state
    FROM states s1
    WHERE
        state = 'INITIAL' AND
        NOT EXISTS (SELECT 1 FROM states s2 WHERE s1.id = s2.id AND s2.state <> 'INITIAL');
    

    我们也可以在这里使用聚合:

    SELECT s1.id, s1.state
    FROM states s1
    INNER JOIN
    (
        SELECT id
        FROM states
        GROUP BY id
        HAVING COUNT(CASE WHEN state <> 'INITIAL' THEN 1 END) = 0
    ) s2
        ON s1.id = s2.id;
    

    另一种选择是自联接:

    SELECT s1.id, s1.state
    FROM states s1
    LEFT JOIN states s2
        ON s1.id = s2.id AND s2.state <> 'INITIAL'
    WHERE s1.state = 'INITIAL' AND s2.id IS NULL;
    

    此查询的工作原理是保留idINITIAL 的所有记录,但不能加入具有相同id 且状态其他 不是INITIAL 的另一条记录。

    【讨论】:

    • 第一个和我的尝试一样吧? :) 但是谢谢!我喜欢有箱子。这是 Postgres 特有的吗?
    • @ChillyPro 我想我没有很清楚地阅读你的问题。第二个选项几乎可以在任何 SQL 数据库上运行。您使用哪个版本完全取决于您;两者都应该有相似的表现(我认为)。
    【解决方案2】:

    使用有从句

    select id from states s1 
    group by id
    having sum(case when state='INITIAL' then 1 else 0 end)=1
    and sum(case when state<>'INITIAL' then 1 else 0 end)=0
    

    【讨论】:

    • 我认为您不需要检查INITIAL存在,因为如果您排除所有 @987654323 的记录@,还有一个组,表示剩下的记录是INITIAL
    【解决方案3】:

    由于 INITIAL 是第一个状态,我选择了只有 1 行的 id(使用计数)

    SELECT id
    FROM (SELECT id, state, COUNT(*) count
          FROM states
          GROUP BY id) as c
    WHERE c.count = 1 
      AND c.state = 'INITIAL'
    

    【讨论】:

    • 谢谢,但我不喜欢这里没有检查状态名称的事实,以防某些错误或人为错误发生删除初始行或从未写入。跨度>
    • @ChillyPro 状态已添加
    猜你喜欢
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2021-04-02
    • 2021-05-19
    • 1970-01-01
    • 2023-02-24
    • 2020-12-08
    • 1970-01-01
    相关资源
    最近更新 更多