Функция Snowflake с Array в качестве параметра завершается с ошибкой Unsupported subquery - PullRequest
1 голос
/ 09 апреля 2020

У меня есть таблица транзакций, и мне нужно сгруппировать похожие записи, и для столбца класса, который может быть уникальным, мне нужно выбрать самое верхнее значение из таблицы поиска (таблица классов), наше значение для аналогичных записей (таблица циклов упорядочена по приоритету).

выберите * из класса;

ID  NAME
2   BETA
6   OMEGA
5   SIGMA
1   ALPHA1
3   GAMMA
4   DELTA
CREATE OR REPLACE FUNCTION "MIN_VALUE"(classlist array)
RETURNS VARCHAR(200)
LANGUAGE SQL
AS '
    select NAME from CLASS 
    where ID in ( select min(ID) from CLASS 
                               where NAME in (select value from table(flatten(input=>classlist))))
';

выберите * из T_DATA;

C_ID    P_ID    D_ID    S_ID    CLASS
1101111 1404    564     1404    BETA
1101111 1404    599     1425    ALPHA
1101111 1404    564     1404    OMEGA
1101111 1404    564     1425    ALPHA
1101111 1404    564     1404    GAMMA
1101111 1404    564     1425    GAMMA
1101111 1404    599     1425    GAMMA
1101111 1404    564     1425    OMEGA

Когда Я пишу запрос, как показано ниже: FINE

выберите MIN_VALUE (array_construct ('OMEGA', 'GAMMA', 'BETA'));

Когда я использую его в реальном запросе, он завершается с SQL ошибкой компиляции: неподдерживаемый тип подзапроса не может быть оценен

select C_ID, P_ID, D_ID, S_ID, MIN_VALUE(class_array) from (
    select C_ID, P_ID, D_ID, S_ID, arrayagg(class) class_array
    from t_data 
    group by C_ID,P_ID,D_ID,S_ID
);

OR

select C_ID,P_ID,D_ID,S_ID,MIN_VALUE(ca) from (
    select C_ID,P_ID,D_ID,S_ID,array_construct(class_array) ca from (
        select C_ID,P_ID,D_ID,S_ID,arrayagg(class) class_array
        from t_data 
        group by C_ID,P_ID,D_ID,S_ID
    )
);

Я ожидаю вывод, как показано ниже из 8 записей выше

select C_ID,P_ID,D_ID,S_ID,array_construct(class_array) ca from (
        select C_ID,P_ID,D_ID,S_ID,arrayagg(class) class_array
        from t_data 
        group by C_ID,P_ID,D_ID,S_ID
    );

Output

C_ID    P_ID    D_ID    S_ID    CLASS_ARRAY
1101111 1404    564     1404    ["OMEGA", "GAMMA", "BETA"]
1101111 1404    599     1425    ["ALPHA", "GAMMA"]
1101111 1404    564     1425    ["ALPHA", "GAMMA", "OMEGA"]

When I use the min_value function on the above class_array that will return a single value based on the priority in the lookup table.

C_ID    P_ID    D_ID    S_ID    CLASS_ARRAY
1101111 1404    564     1404    BETA
1101111 1404    599     1425    ALPHA
1101111 1404    564     1425    ALPHA

Пожалуйста, предложите несколько вариантов, чтобы выяснить, почему функция работает нормально для жестко закодированных значений, но завершается неудачно, если в запросе создается массив и передается как параметр.

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Snowflake имеет некоторые ограничения в поддержке операторов SQL, которые включают некоторые шаблоны SELECT в определениях столбцов . Есть несколько способов переписать запрос выше, чтобы получить желаемый результат:

1) Найдите минимальный идентификатор и затем присоединитесь к таблице классов:

with T as (  
  select C_ID, P_ID, D_ID, S_ID, min(class.id) minclassid
  from t_data join class
     on class.name = t_data.class
  group by C_ID,P_ID,D_ID,S_ID
)
select C_ID, P_ID, D_ID, S_ID, class.name
from T join CLASS on minclassid = class.id;

2) Или используйте функцию Windowing, чтобы получить первое имя класса, упорядоченное по ID внутри группы:

select distinct C_ID, P_ID, D_ID, S_ID, 
   first_value(class.name) over 
     (partition by C_ID, P_ID, D_ID, S_ID order by class.id) name
from t_data join class
on class.name = t_data.class;
0 голосов
/ 10 апреля 2020

Это также можно сделать с помощью фильтра QUALIFY , который позволяет выполнять фильтрацию после стадии выбора, а логарифм фильтра c не отображается в результатах.

with class as (
    select * from values
      (2, 'BETA'),
      (6, 'OMEGA'),
      (5, 'SIGMA'),
      (1, 'ALPHA'),
      (3, 'GAMMA'),
      (4, 'DELTA')  
      v(id, name)
), t_data as (
    select * from values
      (1101111, 1404, 564, 1404, 'BETA'),
      (1101111, 1404, 599, 1425, 'ALPHA'),
      (1101111, 1404, 564, 1404, 'OMEGA'),
      (1101111, 1404, 564, 1425, 'ALPHA'),
      (1101111, 1404, 564, 1404, 'GAMMA'),
      (1101111, 1404, 564, 1425, 'GAMMA'),
      (1101111, 1404, 599, 1425, 'GAMMA'),
      (1101111, 1404, 564, 1425, 'OMEGA')
      v(C_ID, P_ID, D_ID, S_ID, CLASS)
)
select c_id, p_id, d_id, s_id, d.class
from t_data d
join class c on d.class = c.name
qualify row_number() over (partition by c_id, p_id, d_id, s_id order by c.id) = 1;

дает:

C_ID    P_ID    D_ID    S_ID    CLASS
1101111 1404    564     1404    BETA
1101111 1404    564     1425    ALPHA
1101111 1404    599     1425    ALPHA

, что совпадает с более явной / многословной формой:

select c_id, p_id, d_id, s_id, class from (
    select c_id, p_id, d_id, s_id, d.class
        ,row_number() over (partition by c_id, p_id, d_id, s_id order by c.id) as rn
    from t_data d
    join class c on d.class = c.name
)
where rn = 1;

, которая на самом деле такая же механика, как у Стюарта DISTINCT

Если вы если вы действительно хотите сделать это через массив, вы можете упорядочить массив при построении с WITHIN GROUP (ORDER BY ..), а затем вы можете взять первый объект, но методы FIRST_VALUE или QUALIFY должны быть быстрее ... но если есть другие причины для сохранения массива, это может помочь

select C_ID, P_ID, D_ID, S_ID, class_array[0] ca from (
    select C_ID, P_ID, D_ID, S_ID, arrayagg(class) within group (order by class.id) class_array
    from t_data
    join class on t_data.class = class.name
    group by C_ID,P_ID,D_ID,S_ID
);
...