根据一列中不同值的数量在oracle中过滤行

时间:2019-11-20 16:28:38

标签: sql oracle

您好,我在oracle中有一个表:

+ -----+----------+----------+-----------+
| ACC  | TYPE     | BILL_NUM | TYPE_COST |
+ -----+----------+----------+-----------+
| ACC1 | VOICE    |        1 |        10 |
| ACC1 | MMS      |        1 |         5 |
| ACC1 | VOICE    |        2 |        20 |
| ACC1 | MMS      |        2 |        15 |
| ACC1 | VOICE    |        3 |        30 |
| ACC2 | VOICE    |        1 |         3 |
| ACC2 | MMS      |        1 |         4 |
| ACC2 | MMS      |        2 |        14 |
| ACC2 | MMS      |        3 |        24 |
| ACC2 | MMS      |        4 |        34 |
+ -----+----------+----------+-----------+

您可能会看到一个帐户有多个帐单,并且此帐户ACC1有3个帐单(最新为3个),而ACC2有4个帐单(最新为4个)。我想过滤出行,并且只需要查看每个帐户的最新2张账单。在这种情况下,我将使用帐户作为输入。我写了一个查询及其工作方式:

with 
acclist as (
select * from (
select distinct acc,bill_num from  testdata where acc='ACC1' order by bill_num desc )
where rownum<=2
)
select * from testdata td,acclist al where td.bill_num=al.bill_num and td.acc=al.acc

但是我相信这样做有更好的方法。有人可以为我提供更好的解决方案吗? 下面是参考表的创建:

create table TestData
(
ACC VARCHAR(9),
TYPE VARCHAR(20),
BILL_NUM NUMBER(9),
TYPE_COST NUMBER(9)
);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC1', 'VOICE', 1, 10);
insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC1', 'MMS', 1, 5);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC1', 'VOICE', 2, 20);
insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC1', 'MMS', 2, 15);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC1', 'VOICE', 3, 30);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC2', 'VOICE',1, 3);
insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC2', 'MMS', 1, 4);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC2', 'MMS', 2, 14);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC2', 'MMS', 3, 24);

insert into testdata (ACC, TYPE, BILL_NUM, TYPE_COST)
values ('ACC2', 'MMS', 4, 34);
commit;

1 个答案:

答案 0 :(得分:0)

  

我想过滤出行,并且只需要查看每个帐户的最新2张账单

您可以使用row_number()

select *
from (  
    select t.*, row_number() over(partition by acc order by bill_num desc) rn
    from mytable t
) t
where rn <= 2

Demo on DB Fiddle

ACC  | TYPE  | BILL_NUM | TYPE_COST
:--- | :---- | -------: | --------:
ACC1 | VOICE |        3 |        30
ACC1 | VOICE |        2 |        20
ACC2 | MMS   |        4 |        34
ACC2 | MMS   |        3 |        24

修改

如果您想允许联系(这意味着您可以在结果集中的每个帐户获得两个以上的记录),则可以改用dense_rank()

select *
from (  
    select t.*, dense_rank() over(partition by acc order by bill_num desc) rn
    from mytable t
) t
where rn <= 2

Demo

ACC  | TYPE  | BILL_NUM | TYPE_COST
:--- | :---- | -------: | --------:
ACC1 | VOICE |        3 |        30
ACC1 | VOICE |        2 |        20
ACC1 | MMS   |        2 |        15
ACC2 | MMS   |        4 |        34
ACC2 | MMS   |        3 |        24