Несколько внешних предложений применения не возвращают правильный результат? - PullRequest
0 голосов
/ 27 декабря 2018

Следующий запрос должен вернуть все ненулевые значения для столбца n.c, так как C не может иметь значение NULL.

select  distinct A, B, a.C, n.C
from    o
        outer apply ( -- Get first C which Status = 1, if there is any
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a
        outer apply ( -- Get the latest C otherwise (ID is identity column)
            select C
            from o i where i.A = o.A and i.B = o.B and ROWNUM = 1
            order by ID desc) n

Однако, n.C будет нулевым, если a.C будет нулевым.И он вернет желаемое значение, если я уберу внешнее применение a.

select  distinct A, B, n.C
from    o
        outer apply (
            select C
            from o i where i.A = o.A and i.B = o.B and ROWNUM = 1
            order by ID desc) n

Это ошибка Oracle?

Кстати, он работает, как и ожидалось, если я переключаю два outer apply?

select  distinct A, B, a.C, n.C
from    o
        outer apply (
            select C
            from o i where i.A = o.A and i.B = o.B and ROWNUM = 1
            order by ID desc) n
        outer apply (
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a

Версия Oracle

Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE    12.1.0.2.0  Production
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production

Тестовые данные

CN из 2, 2 равно нулю:

with o(ID, A, B, C, Status) as (
    select 1, 1, 1, 1, 1 from dual union all
    select 2, 2, 2, 2, 0 from dual union all
    select 3, 2, 2, 2, 0 from dual
    )
select  distinct A, B, a.C Ca, n.C Cn
from    o
        outer apply ( -- Get first C which Status = 1, if there is any
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a
        outer apply ( -- Get the latest C otherwise (ID is identity column)
            select C
            from o i where i.A = o.A and i.B = o.B and ROWNUM = 1
            order by ID desc) n

возвращает

A   B   CA  CN
1   1   1   1
2   2   NULL    NULL

CN из 2, 2 нетnull после перемещения outer apply (...) n:

with o(ID, A, B, C, Status) as (
    select 1, 1, 1, 1, 1 from dual union all
    select 2, 2, 2, 2, 0 from dual union all
    select 3, 2, 2, 2, 0 from dual
    )
select  distinct A, B, a.C Ca, n.C Cn
from    o
        outer apply ( -- Get the latest C otherwise (ID is identity column)
            select C
            from o i where i.A = o.A and i.B = o.B and ROWNUM = 1
            order by ID desc) n
        outer apply ( -- Get first C which Status = 1, if there is any
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a

возвращает

A   B   CA  CN
1   1   1   1
2   2   NULL    2

И следующий запрос (который пытается сделать ROWNUM более решительным) все же дал неверный результат.

with o(ID, A, B, C, Status) as (
    select 1, 1, 1, 1, 1 from dual union all
    select 2, 2, 2, 2, 0 from dual union all
    select 3, 2, 2, 2, 0 from dual
    )
select  distinct A, B, a.C Ca, n.C Cn
from    o
        outer apply ( -- Get first C which Status = 1, if there is any
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a
        outer apply ( -- Get the latest C otherwise (ID is identity column)
            select * from (
                select C
                from o i where i.A = o.A and i.B = o.B 
                order by ID desc) x
            where ROWNUM = 1) n

1 Ответ

0 голосов
/ 27 декабря 2018

Во втором внешнем операторе apply вы ограничиваете результаты до ROWNUM = 1, но также имеете предложение order by, однако ROWNUM не зависит от порядка сортировки.Он представляет порядок, в котором Oracle извлекает строки из БД, что может не соответствовать запрошенному порядку отображения.Используя ROWNUM = 1, вы фактически отменили свой заказ на.Вместо этого вы захотите изменить свое второе внешнее применение, используя сгенерированный номер строки на основе желаемой сортировки и критериев фильтрации.

with o(ID, A, B, C, Status) as (
    select 1, 1, 1, 1, 1 from dual union all
    select 2, 2, 2, 2, 0 from dual union all
    select 3, 2, 2, 2, 0 from dual
    )
select  distinct A, B, a.C CA, n.C CN
from    o
        outer apply ( -- Get first C which Status = 1, if there is any
            select C 
            from o i where i.A = o.A and i.B = o.B and STATUS = 1 and ROWNUM = 1) a
        outer apply ( -- Get the latest C otherwise (ID is identity column)
            select C
            from (select o.*, row_number() over (partition by a, b order by id desc) rn from o) i 
            where i.A = o.A and i.B = o.B and rn = 1
            order by ID desc) n

Обратите внимание, однако, что при ID = 2 запись идентифицируется как RN= 1 является неопределенным, это может быть либо первая, либо вторая запись, поскольку единственным критерием сортировки является идентификатор.Не то, чтобы это имело значение для ваших образцов данных, так как обе записи идентичны, однако, если бы были различия в C, результат мог бы быть непредсказуемым.

Более простой подход, который возвращает те же данные, может заключаться в использованиивместо этого этот запрос полностью исключает проблему внешнего применения:

select a, b
     , max(case status when 1 then C end) keep (DENSE_RANK FIRST ORDER BY status desc, rownum) CA
     , max(c) keep (DENSE_RANK LAST ORDER by id) CN
  from o
 group by a,b;

Результаты обоих запросов одинаковы:

A   B   CA  CN
1   1   1   1
2   2       2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...