簡體   English   中英

當必須根據條件對記錄進行分組時,如何最多選擇 x 行

[英]How to select up to x rows when records have to be grouped based on criteria

我想創建查詢,我最多選擇 x 行,記錄按一個 id 分組,並且整個組必須是查詢的結果。 我基於過濾的值存儲在 p_id 列中,具有相同值的行創建組。 在該表的情況下:

    p_id    age
0   00170   64  
1   00170   64  
2   00201   24  
3   00201   64  
4   00201   64  
5   00300   24  
6   00300   20  

我想選擇 4 行,但是因為 p_id 為 00170,00201 的組總共有 5 條記錄,所以我得到了:

0   00170   64 
1   00170   64

如果我選擇 5 行,我會得到:

0   00170   64 
1   00170   64 
2   00201   24 
3   00201   64 
4   00201   64 

如果我要選擇 6 行,我會得到(p_id 00300 是 2 條記錄,因此不包括在內,因為總和超過 6):

0   00170   64 
1   00170   64 
2   00201   24 
3   00201   64 
4   00201   64 

所以整個組都返回了。 我正在使用 oracle db,使用 ROWNUM 可以輕松選擇 x 行。 當我嘗試使用附加條件達到一定數量的行時,我迷路了。

甲骨文設置

CREATE TABLE test_data ( p_id, age ) AS
SELECT '00170', 64 FROM DUAL UNION ALL
SELECT '00170', 64 FROM DUAL UNION ALL
SELECT '00201', 24 FROM DUAL UNION ALL
SELECT '00201', 64 FROM DUAL UNION ALL
SELECT '00201', 64 FROM DUAL UNION ALL
SELECT '00300', 24 FROM DUAL UNION ALL  
SELECT '00300', 20 FROM DUAL;

查詢

對行進行排序,然后找到每個組的最大行號,然后過濾以僅返回最大行號包含在所需行限制中的組:

SELECT p_id,
       age
FROM   (
  SELECT t.*,
         MAX( ROWNUM ) OVER ( PARTITION BY p_id ) AS grp
  FROM   (
    SELECT *
    FROM   test_data
    ORDER BY p_id
  ) t
)
WHERE  grp <= 4;

輸出

\n P_ID | 年齡\n :---- |  ——:\n 00170 |  64\n 00170 |  64\n

如果您將最后一行更改為 5,則它將返回 5 行並將其更改為 6,則它仍將返回 5 行。

db<> 在這里擺弄

我會用窗口計數和過濾來解決這個問題:

select p_id, age
from (select p_id, age, count(*) over(order by p_id) cnt from mytable t) t
where cnt <= 5
order by p_id

您可以根據需要更改cnt <= 5

DB Fiddle 上的演示

cnt <= 4

P_ID | AGE
---: | --:
 170 |  64
 170 |  64

cnt <= 5

P_ID | AGE
---: | --:
 170 |  64
 170 |  64
 201 |  24
 201 |  64
 201 |  64

cnt <= 6

P_ID | AGE
---: | --:
 170 |  64
 170 |  64
 201 |  24
 201 |  64
 201 |  64

GMB 的回答很好。 但是可以通過使用RANK()來簡化它。 此功能恰好做的正是你想要的東西:

select p_id, age
from (select t.*,
             rank() over (order by p_id) as rnk
      from t
     ) t
where rnk <= 5
order by p_id;

更重要的是,如果p_id值沒有排序,那么您可能需要一個額外的步驟:將某個排序列的最小值分配給每個p_id 讓我稱之為排序列id

select p_id, age
from (select t.*,
             rank() over (order by p_id_grp) as rnk
      from (select t.*, min(id) over (partition by p_id) as p_id_grp
            from t
           ) t
     ) t
where rnk <= 5
order by p_id;

這是一個典型的 Top-N 查詢:

將 ROWNUM 與有序視圖一起使用以獲得正確的排序:

SELECT p_id, age
FROM   (SELECT p_id, age
        FROM   table
        ORDER BY age DESC)
WHERE ROWNUM <= 4;

對於 Oracle v 12c 以后的版本,有新的 FETCH 子句:

SELECT p_id, age
FROM   table
GROUP BY p_id
FETCH FIRST 4 ROWS ONLY;

更多資源: https : //oracle-base.com/articles/misc/top-n-queries

暫無
暫無

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

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