2014-09-30 66 views
0

我有一個包含三列x, y, z的表格。我想寫一個查詢,在每個PARTITION BY x中,返回包含第一個不同值y的行。,選擇N個不同值的行

下面是n = 2樣品 - 的y在第一分區中的第一2倍不同的值是1和2,以及圖4和5中的第二個分區,所以用的y這些值的所有行均包括在內。

x y z included? 
---------------------- 
1 1 1 true 
1 1 2 true 
1 2 3 true 
1 2 4 true 
1 3 5 false 
1 3 6 false 
2 4 7 true 
2 4 8 true 
2 5 9 true 
2 5 10 true 
2 6 11 false 
2 6 12 false 

有一個related question與每個分區選擇n行交易,但不與不同價值觀的一部分處理。

回答

2

我「米不知道你的意思是‘第一’。SQL表代表無序集合所以,我假設你的意思是‘最小的’

可以使用dense_rank()做到這一點:

select t.* 
from (select t.*, dense_rank() over (partition by x order by y) as seqnum 
     from atable t 
    ) t 
where seqnum <= 2; 
+0

如果我是從一個指定一些任意排序的子查詢中進行選擇,並且想要採用那些第一個'n'? – rcrogers 2014-10-01 01:44:40

+0

@rcrogers。 。 。您可以將排序放入'order by'子句中。 – 2014-10-01 02:04:07

+0

是否有外部查詢尊重內部查詢的排序方式,沒有外部查詢也指定它? – rcrogers 2014-10-01 02:20:46

2

您可以使用desnse_rankrow_number組合來消除重複:

with a as (
    select 
    x, y, z, 
    dense_rank() over (partition by x order by y) rk, 
    row_number() over (partition by x, y order by z) rn 
    from 
    t 
) select 
    x, y, z 
from 
    a 
where 
    rk <= 2 and 
    rn = 1; 

這產生1, 2, 4, 5

這個,你可以通過加入放回噸得到想要的結果:

with a as (
    select 
    x, y, z, 
    dense_rank() over (partition by x order by y) rk, 
    row_number() over (partition by x, y order by z) rn 
    from 
    t 
) select 
    t.* 
from 
    t 
where 
    exists (
    select 
     'x' 
    from 
     a 
    where 
     a.y = t.y and 
     a.rk <= 2 and 
     a.rn = 1 
); 

Example SQLFiddle

雖然,以這種方式使用exists,使得重複無關,所以你可以這樣做:

with a as (
    select 
    x, y, z, 
    dense_rank() over (partition by x order by y) rk 
    from 
    t 
) select 
    t.* 
from 
    t 
where 
    exists (
    select 
     'x' 
    from 
     a 
    where 
     a.y = t.y and 
     a.rk <= 2 
); 

Example SQLFiddle