Выберите строки на основе нескольких условий - PullRequest
1 голос
/ 10 февраля 2020

У меня есть таблица, из которой я должен выбрать несколько строк на основе следующих условий:

  1. Если существует несколько строк с одним и тем же DocumentRef, выберите все строки, если BlockNumber пуст для все строки
  2. Если существует несколько строк с одним и тем же DocumentRef, выберите только 1 строку (упорядоченную по DocumentId как c) с BlockNumber IS NOT EMPTY
  3. Если с DocumentRef существует только одна строка выберите его независимо от чего-либо

Таблица: enter image description here

Я пытался сгруппировать его по DocumentRef и отфильтровать с имеющим, но имеющим может иметь только агрегат функции. Я думаю, что мне придется предоставить несколько условий в отделении от ИЛИ. Пожалуйста, дайте мне некоторое направление.

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Использовать оконные функции:

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
                          );

Подзапрос возвращает пустой набор, если все blocknumber s NULL. По определению, любой идентификатор документа соответствует условию в пустом наборе.

1 голос
/ 10 февраля 2020

Присоедините таблицу к запросу, который возвращает для каждого documentref максимальное documentid для всех blocknumber s, которые не 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)

См. Демоверсию . Результаты:

> 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
...