【问题标题】:Return all the rows for id's that have all three seq number present返回具有所有三个序列号的 id 的所有行
【发布时间】:2017-10-29 03:03:25
【问题描述】:

我有一个看起来像这样的表:

table1

+----+-----+------+
| id | seq | test |
+----+-----+------+
|  1 |   1 | HR   |
|  1 |   2 | RR   |
|  2 |   1 | HR   |
|  2 |   2 | RR   |
|  2 |   3 | OXY  |
|  3 |   1 | HR   |
|  3 |   2 | RR   |
|  4 |   1 | HR   |
|  4 |   2 | RR   | 
|  4 |   3 | OXY  | 
+----+-----+------+

我想得到如下结果表。也就是说,只有当特定 id 的所有三个序列号都存在时,我才需要拥有特定 id 的所有行:

+----+-----+------+
| id | seq | test |
+----+-----+------+
|  2 |   1 | HR   |
|  2 |   2 | RR   |
|  2 |   3 | OXY  |
|  4 |   1 | HR   |
|  4 |   2 | RR   |
|  4 |   3 | OXY  | 
+----+-----+------+

我期待着编写一个 plpgsql 函数来为我提供解决方案。我对 plpgsql 和一般编程比较陌生。如果有人帮助我获得结果,那就太好了。

到目前为止,这是我的功能的样子,但它不完整:

CREATE OR REPLACE FUNCTION test()
returns SETOF table1 AS $$
DECLARE
    cur CURSOR FOR
        SELECT *
        FROM table1
        ORDER by id;
    rec_cur RECORD;
    counter INTEGER DEFAULT 0;

BEGIN 
    OPEN cur;

    FETCH FIRST FROM cur INTO rec_cur;
    MOVE RELATIVE +1 FROM cur;

    LOOP
        FETCH cur INTO rec_cur;
        EXIT WHEN NOT FOUND;

        IF rec_cur.seq = 1 AND counter = 0 THEN
        RETURN NEXT rec_cursor;
        END IF;

    END LOOP;
    CLOSE cur;
    RETURN;

END ; $$ 
LANGUAGE PLPGSQL STABLE PARALLEL SAFE;

【问题讨论】:

  • 如果您将表格放在代码块中,它将保持格式化
  • 非常感谢。我正要这样做。无论如何谢谢你:)
  • 与往常一样,实际的表定义(CREATE TABLE 语句)将有助于澄清。最重要的是:(id, seq) 是否定义为唯一且两列都不为空?还有其他可靠的元信息吗?并且总是提到你的 Postgres 版本。 Edit 需要澄清的问题。
  • @ErwinBrandstetter 非常感谢您提供的信息。当我问下一个问题时,我肯定会考虑你提到的几点。

标签: sql postgresql plpgsql relational-division


【解决方案1】:

您的问题不完整。
如果我们可以假设存在带有seq = 1seq = 2 的行,如果有一行带有seq = 3 的行对于相同的id,然后它变得便宜又简单:

SELECT *
FROM  (SELECT id FROM table1 WHERE seq = 3) x
JOIN   table1 t USING (id)
-- ORDER BY id, seq;  -- unclear whether you need sorted output.

还假设 (id, seq) 定义为 UNIQUE 和两列 NOT NULL

如果您需要优化读取性能,请添加部分索引:

CREATE INDEX foo ON table1 (id) WHERE seq = 3;

Since Postgres 9.6 this can be used in an index-only scan.

当然,您还需要(id) 的索引。 (id, seq) 上的索引如果你说UNIQUE 约束也可以完成这项工作。相关:

不管怎样,都是的情况。如果我们不能假设seq 中的顺序值,这里有一个技术库来识别符合条件的id

【讨论】:

  • 表格是这样的,对于唯一的 id,肯定有 seq=1 和 seq=2 对应于 test=HR 和 test=RR。但是对于某些 id,有 seq=3 对应于 test=OXY。我只对具有所有 3 seq 的 id 感兴趣。而且这两列都没有 NULL 值。附加信息。真的很棒,我很感激。再次感谢您。
【解决方案2】:

游标绝对不是正确的方法。您可以使用聚合和having 轻松获取 id:

select id
from t
where seq in (1, 2, 3)
group by id
having count(seq) = 3;

那么获取原始行,有多种方式:

select t.*
from t join
     (select id
      from t
      where seq in (1, 2, 3)
      group by id
      having count(seq) = 3
     ) tt
     on t.id = tt.id;

编辑:

如果序列号总是从 1 开始并且没有间隙,那么窗口函数就是要走的路:

select t.*
from (select t.*, max(t.seq) over (partition by t.id) as maxseq
      from t
     ) t
where maxseq = 3;

【讨论】:

  • 既然seq 只能有来自1, 2, 3 的值,那么where seq in (1, 2, 3) 有什么影响吗?
  • @MajidFouladpour 。 . .问题没有明确说明是这种情况。
猜你喜欢
  • 2020-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多