簡體   English   中英

SQL 分組依據:select 值,其中另一列有其最小值/最大值

[英]SQL group by: select value where another column has its min/max

我想按一列分組,同時獲取第二列的最小值和最大值,並且(這是棘手的部分。)從第三列獲取值,其中第二列在組中具有其最小值。

例子:

我的表:

ID     TS     GRP
==================
 1     20      A
 2     20      B
 3     10      A
 4     30      A
 5     10      B
 6     40      A

期望的結果(ID 應該是 TS 最小值的記錄中的值):

ID    MIN_TS   MAX_TS   GRP
============================
 3      10       40      A
 5      10       20      B

一般來說,分組查詢很容易:

SELECT <???> AS ID, MIN(TS) AS MIN_TS, MAX(TS) AS MAX_TS, GRP
FROM MyTable
GROUP BY GRP

但是 ID 部分呢? 它不適用於分組,對嗎? 但為什么? 最好的解決方法是什么?

在子查詢中進行匯總,然后在另一個子查詢中查找每個組的ID:

SELECT
  (SELECT TOP(1) id FROM MyTable WHERE grp = agg.grp ORDER BY ts DESC) AS id,
  min_ts, max_ts, grp
FROM (SELECT min(ts) AS min_ts, max(ts) AS max_ts, grp
      FROM MyTable
      GROUP BY grp) agg

或使用窗口功能:

SELECT id, min_ts, max_ts, grp
FROM (SELECT 
        id,
        min(ts) OVER (PARTITION BY grp) min_ts,
        max(ts) OVER (PARTITION BY grp) max_ts,
        grp,
        row_number OVER (PARTITION BY grp ORDER BY ts) rn
      FROM MyTable)
WHERE rn = 1;

該查詢使用窗口函數來計算每個組的min_tsmax_ts ,然后過濾以僅包括每個組的第一行(按ts排序)。

有點晚了,但對於未來的人......

我可以提出另一種解決方案,它與現有的有點不同,它的想法基本相同,但它以另一種方式實現(而且它可能更快一點?)。

所以你基本上可以在子查詢中進行所有分組和聚合(使用WITH ),然后在該查詢和你的原始表之間使用INNER JOIN來獲得你想要的東西,它會是這樣的......

WITH values AS (
  SELECT
    MIN(ts) as min_ts,
    MAX(ts) AS max_ts,
    grp
  FROM MyTable
  GROUP BY grp
)

SELECT
  tb.id AS id,
  v.min_ts AS min_ts,
  v.max_ts AS max_ts,
  tb.grp AS grp
FROM MyTable tb
INNER JOIN values v ON v.grp = tb.grp AND v.min_ts = tb.ts;

這有點簡單,也更直觀(至少對我而言)。

我已經在 Postgres DB 上對此進行了測試,並針對以下數據

 id | ts | grp 
----+----+-----
  7 |  5 | A
  3 | 10 | A
  1 | 20 | A
  5 | 30 | A
  4 | 10 | B
  2 | 20 | B
  6 | 30 | B
  8 | 60 | B

它給出了以下結果

 id | min_ts | max_ts | grp 
----+--------+--------+-----
  7 |      5 |     30 | A
  4 |     10 |     60 | B

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM