如何有条件地将行附加到结果集?

Gaj*_*jus 2 postgresql

我有一个复杂的SELECT查询表,用于标识event_id和之间的关系attribute。这是一个VALUES表达式的简化:

SELECT event_id, attribute
FROM (
  VALUES
    (1, '2D'),
    (1, 'IMAX'),
    (2, 'IMAX'),
    (3, '3D')
) event_attribute (event_id, attribute)
Run Code Online (Sandbox Code Playgroud)

我想(event_id, '2D')为每个event_id尚未与3Dor2D属性关联的记录都包含一个额外的记录。如何有条件地将行附加到结果集?

在上表的情况下,预期结果将是:

(1, '2D'),
(1, 'IMAX'),
(2, 'IMAX'),
(2, '2D'),
(3, '3D')
Run Code Online (Sandbox Code Playgroud)

还有一个表格event,每个相关id.

Erw*_*ter 5

假设(就像后来添加的那样)一个event具有所有相关唯一性的单独表id- 这有助于提高性能:

WITH cte(event_id, attribute) AS (
   -- big SELECT query goes here instead of the VALUES expression
   VALUES
    (1, '2D'),
    (1, 'IMAX'),
    (2, 'IMAX'),
    (3, '3D')
   )
TABLE cte
UNION ALL
SELECT e.id, '2D'
FROM   event e
LEFT   JOIN cte ON cte.event_id = e.id
               AND cte.attribute IN ('2D','3D')
WHERE  cte.event_id IS NULL;
Run Code Online (Sandbox Code Playgroud)

有关的:

如果您的查询仅返回 all 的一个子集event_id,则不能event像这样使用该表进行简化。没有表的替代方案event

WITH cte AS (
   -- big SELECT query goes here instead of the VALUES expression
   VALUES
    (1, '2D'),
    (1, 'IMAX'),
    (2, 'IMAX'),
    (3, '3D')
   )
TABLE cte
UNION ALL
SELECT event_id, '2D'
FROM   cte
GROUP  BY 1
HAVING count(*) FILTER (WHERE attribute IN ('2D', '3D')) = 0;
Run Code Online (Sandbox Code Playgroud)

这有点类似于您自己回答的问题,只是更短,更快一些。特别是聚合FILTER条款应该是有用的。有关的:

由于来自 CTE 的派生表上没有索引,因此第二个查询开始时可能会更快。