Postgresql

選擇按“附加”指示器分組的行

  • January 4, 2018

我有一個(預先存在的,不,我不是這樣設計的!)這樣的模式/數據集:

CREATE TABLE t(id,name,seq,addon,kind)
AS VALUES
   ( 1234::int, 'A' , 345::int, 'f'::bool, 'c'  ),
   ( 1235     , NULL, 346     , 't'      , NULL ),
   ( 1236     , NULL, 347     , 't'      , NULL ),
   ( 2345     , 'B' , 348     , 'f'      , 'x'  ),
   ( 2346     , NULL, 349     , 't'      , NULL ),
   ( 3456     , 'C' , 350     , 'f'      , 'c'  ),
   ( 3457     , NULL, 351     , 't'      , NULL );

在哪裡:

  1. “id”欄位只是一個 SQL 序列(不保證順序)
  2. “seq”欄位保證在整個表格中是連續的,例如表格通常在此列上排序。
  3. “addon”欄位表示一組相關條目,例如,TRUE 條目與最近的具有較低“seq”的 FALSE 條目相關。

我想選擇所有帶有“kind”=‘x’的行及其所有關聯的“addon”行,而不為其他種類獲取任何其他“addon”行。

例如:

SELECT * FROM t WHERE kind = 'x' AND ???

會給我:

 id  | name | seq  |addon | kind |
------+------+------+------+------+...
2345 | "B"  | 348  |  f   | "x"  |
2346 |      | 349  |  t   |      |

我有 PostgreSQL 9.6…

您只需要創建一個真正的分組。這裡我們使用一個視窗函式count(x)來計算所有的東西NOT NULL。試試這個簡化的例子,

SELECT count(a) OVER ()
FROM ( VALUES (true),(false) ) AS t(a);

為了計算我們想要OR的,如果 lhs 不是,我們使用 which 評估 rhs true。所以在這裡我們測試是否行IS FALSE(如果值為假則返回真),如果條件不評估為真(意味著值為真或空)我們返回null(所以count(x)跳過它)。這是完整的查詢,

SELECT *,
 count((addon IS FALSE) OR NULL) OVER (ORDER BY seq) AS grp
FROM t

 id  | name | seq | addon | kind | grp 
------+------+-----+-------+------+-----
1234 | A    | 345 | f     | c    |   1
1235 |      | 346 | t     |      |   1
1236 |      | 347 | t     |      |   1
2345 | B    | 348 | f     | x    |   2
2346 |      | 349 | t     |      |   2
3456 | C    | 350 | f     | c    |   3
3457 |      | 351 | t     |      |   3
(7 rows)

現在你可以輕鬆地做任何你想做的事情了..

WITH t AS (
 SELECT *,
   count((addon IS FALSE) OR NULL) OVER (ORDER BY seq) AS grp
 FROM t
)
SELECT *
FROM t AS t1
WHERE EXISTS (
 SELECT 1
 FROM t AS t2
 WHERE addon IS FALSE
   AND kind = 'x'
   AND t1.grp = t2.grp
)
ORDER BY seq;

要在其他地方查看此模式,請使用此搜尋查看gaps-and-islandspostgresql

引用自:https://dba.stackexchange.com/questions/194539