根据多个条件选择行

时间:2020-02-09 21:05:35

标签: sql select group-by db2

我有一个表,必须根据以下条件从中选择一些行。

  1. 如果同一DocumentRef存在多于一行,则如果所有行的BlockNumber为空,则选择所有行
  2. 如果同一DocumentRef存在多于一行,则仅选择1行(按DocumentId asc排序),其BlockNumber不为空
  3. 如果DocumentRef仅存在一行,则无论是否选择该行

表: enter image description here

我试图通过DocumentRef将其分组,并使用具有但只能具有聚合函数的过滤器。我认为在用OR分隔时必须提供多个条件。请给我一些指导。

2 个答案:

答案 0 :(得分:1)

将表加入到一个查询中,该查询为所有documentref(如果不是documentidblocknumber的所有null返回最大null都是null

select t.*
from tablename t inner join (
  select 
    documentref,
    max(case when blocknumber is not null then documentid end) maxid 
  from tablename
  group by documentref
) d on d.documentref = t.documentref 
   and t.documentid = coalesce(d.maxid, t.documentid)

请参见demo
结果:

> DOCUMENTID | DOCUMENTREF | WARDID | BLOCKNUMBER
> ---------: | ----------: | -----: | ----------:
>  203962537 |   100000126 |      B |           A
>  203962538 |   100000130 |      B |           A
>  203962542 |   100000151 |   null |        null
>  203962543 |   100000151 |   null |        null
>  203962544 |   100000180 |      B |           A
>  203962546 |   100000181 |      B |           A
>  203962551 |   100000185 |   null |        null
>  203962552 |   100000186 |      B |           A

答案 1 :(得分:1)

使用窗口功能:

select t.*
from (select t.*,
             sum(case when blocknumber is not null then 1 else 0 end) over (partition by documentref) as num_bn_notnull,
             rank() over (partition by documentref
                          order by (case when blocknumber is not null then documentid end) desc nulls last
                         ) as rnk
      from t
     ) t
where num_bn_notnull = 0 or
      rnk = 1;

或者,您可以使用exists子句:

select t.*
from t
where not exists (select 1
                  from t t2
                  where t2.documentref = t.documentref and
                        t2.blocknumber is not null
                 ) or
       t.documentid = (select max(t2.documentid)
                       from t t2
                       where t2.documentref = t.documentref and
                             t2.blocknumber is not null
                      );

这可以利用(documentref, blocknumber, documentid)上的索引。

实际上,通过对SQL语言的怪癖,我认为这同样有效:

select t.*
from t
where t.documentid >= any (select t2.documentid
                           from t t2
                           where t2.documentref = t.documentref and
                                 t2.blocknumber is not null
                           order by t2.documentid
                           fetch first 1 row only
                          );

如果所有blocknumberNULL,则子查询返回一个空集。根据定义,任何文档ID都符合空集上的条件。