我有一张看起来像这样的表:
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的所有三个seq编号都存在时,我才需要拥有特定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;
答案 0 :(得分:2)
游标绝对不是正确的方法。您可以使用聚合和having
:
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;
答案 1 :(得分:1)
你的问题不完整
如果我们可以假设存在包含seq = 1
和seq = 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
约束,则存在该作业)。相关:
无论哪种方式,都是relational-division的情况。如果我们不能在id
中假设顺序值,那么这里有一套识别合格seq
的技术: