2014-09-30 50 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