Ошибка «Не выражение GROUP BY» при использовании пользовательских вызовов функций в Факторизованном подзапросе - PullRequest
0 голосов
/ 25 июня 2018

Давайте предположим, что у меня есть эти таблицы (игнорируйте, что они по сути одинаковы, фактическая настройка более сложна, чем эта):

create table inbound (
    id number(19,0) not null,
    created_on timestamp(6),
    place_id number(19,0),
    qty_amount float(126),

    constraint "inbound_pk" primary key (id),
    constraint "inbound_place_FK" foreign key (place_id)
        references place (id) on delete cascade 
);

create table outbound (
    id number(19,0) not null,
    created_on timestamp(6),
    place_id number(19,0),
    qty_amount float(126),

    constraint "outbound_pk" primary key (id),
    constraint "outbound_place_FK" foreign key (place_id)
        references place (id) on delete cascade 
)

Затем у меня есть этот запрос:

with aligned_in (start_date, place_id, total) as (
    select
        get_week_start(place_id, created_on) start_date,
        place_id,
        sum(qty_amount) total
    from inbound
    where <....>
    group by
        get_week_start(place_id, created_on), place_id
),
aligned_out (start_date, place_id, total) as (
    select
        get_week_start(place_id, created_on) start_date,
        place_id,
        sum(qty_amount) total
    from outbound
    where <....>
    group by get_week_start(place_id, created_on), place_id
)

select
   start_date,
   place_id,
   aligned_in.total total_in,
   aligned_out.total total_out
from aligned_in
  left outer join aligned_out using(place_id, start_date)

По какой-то причине этот запрос при выполнении в Oracle 12.2.0.1.0 выдает

ORA-00979: не выражение GROUP BY

ошибкасо строкой, указывающей на строку с вызовом get_week_start.

В процессе работы с ним я также обнаружил следующее:

  • Подзапросы для aligned_in и aligned_out сам по себе может выполняться совершенно нормально
  • Удаление вызова на get_week_start из проекции подзапросов исправляет это - предложение group by без этого вызова в проекции работает (но, очевидно, многое меняет то, как этот запрос написан ивыполняется)
  • (вещь, которая меня больше всего смущает) Этот точный запрос без каких-либо изменений выполняется полностью в Oracle 11.2.0.2.0
  • Большая часть информации о ORA-00979 не оченьполезно, потому что это не кажется применимымвообще на мой запрос

Здесь get_week_start - довольно простая функция, чтобы узнать, каким будет начало рабочей недели при данном Place (это данные клиента).Из-за того, как это определено, эта функция не является детерминированной.Однако я натолкнулся на предложения о том, что такие функции должны быть помечены как детерминированные, и попытался сделать это, просто чтобы посмотреть, что происходит - и это не помогло.

Итак, почему это происходит?

Что изменилось между версиями 11.2.0 и 12.2.0, что вызвало это?Мне не хватает какой-либо опции конфигурации?Можно ли это исправить, не переписывая запрос?

Редактировать :

Пример версии get_week_start, как указано в комментариях:

create function get_week_start(place_id number, week_day date)
    return date
as
    start_date date;
begin
    begin
        select
            trunc(next_day(week_day, o.business_week_start)) - 7
                into start_date
        from place
            inner join place_owner o on o.id = place.owner_id
        where place.id = place_id;

        return stat_date;
    exception
    when others then return null;
    end;
end get_week_start;

Примертаблицы для place и place_owner:

create table place_owner (
    id number(19,0) not null,
    name varchar2(255) not null,
    business_week_start varchar2(64) not null,

    constraint "place_owner_pk" primary key (id)
);

create table place (
    id number(19, 0) not null,
    name varchar2(255) not null,
    owner_id number(19,0) not null,

    constraint "place_pk" primary key (id),
    constraint "place_unq" unique (owner_id, name),
    constraint "place_owner_fk" foreign key (owner_id)
        references place_owner (id) on delete cascade
);

1 Ответ

0 голосов
/ 25 июня 2018

Я бы попробовал CROSS/OUTER APPLY (Oracle 12c):

with aligned_in (start_date, place_id, total) as (
    select
        s.start_date,
        place_id,
        sum(qty_amount) total
    from inbound
    cross apply (SELECT get_week_start(place_id, created_at) AS start_date 
                FROM dual) s 
    where <....>
    group by
         s.start_date, place_id
),
...

Другой подход:

with aligned_in (start_date, place_id, total) as (
    SELECT start_date,
           place_id,
           sum(qty_amount) total
    FROM (select get_week_start(place_id, created_at) AS  start_date,
                 place_id,
                 qty_amount
           from inbound
           where <....>) sub
    group by start_date, place_id
),  
-- ...
...