Snowflake - возвращает разные (не похожие) значения между двумя массивами - PullRequest
0 голосов
/ 31 октября 2019

После просмотра документации Snowflake я обнаружил функцию с именем array_intersection(array_1, array_2), которая будет возвращать общие значения между двумя массивами, но мне нужно отобразить массив со значениями, которых нет ни в одном из массивов.

Пример 1:

Допустим, у меня в таблице есть два следующих массива

array_1 = ['a', 'b', 'c', 'd', 'e']
array_2 = ['a', 'f', 'c', 'g', 'e']

Мой запрос:

select
  array_intersection(array_1, array_2)
from myTable

Текущий вывод:

['a', 'c', 'e']

Но я ожидаю вывод как:

['f', 'g']

Пример 2:

Допустим, у меня есть следующиедва массива в моей таблице

array_1 = ['u', 'v', 'w', 'x', 'y']
array_2 = ['u', 'v', 'i', 'x', 'k']

Мой запрос:

select
  array_intersection(array_1, array_2)
from myTable

Текущий вывод:

['u', 'v', 'x']

Но я ожидаю вывод как:

['w', 'y', 'i', 'k']

как это можно сделать в Снежинке? есть предложения?

Ответы [ 3 ]

3 голосов
/ 31 октября 2019

Операция set в этом вопросе - это то, что математики называют дизъюнктивным объединением .
. Это тот случай, когда винт ARRAY, возможно, не оптимально обрабатывается молотком SQL.

Одна вещь состоит в том, чтобы заставить изолированный запрос работать с базовым сценарием, совсем другое дело - создать поддерживаемый реальный запрос, который также содержит другие сложности.

JavaScript идеален для обработки вычислений с множествами, иидеально подходит для этой задачи:

CREATE OR REPLACE FUNCTION ARRAY_DISJUNCTIVE_UNION(A1 ARRAY, A2 ARRAY)
RETURNS ARRAY LANGUAGE JAVASCRIPT AS
'return [...A1.filter(e => !A2.includes(e)),...A2.filter(e => !A1.includes(e))]';
1 голос
/ 31 октября 2019
with myTable as (
select array_construct('a', 'b', 'c', 'd', 'e') as a1
    ,array_construct('a', 'f', 'c', 'g', 'e') as a2
)
select a1, a2, array_intersection(a1, a2)
from myTable;

показывает, что мы работаем с одними и теми же данными.

with myTable as (
    SELECT array_construct('a', 'b', 'c', 'd', 'e') as a1
    ,array_construct('a', 'f', 'c', 'g', 'e') as a2
), seq_myTable as (
    SELECT seq8() as seq
    ,t.*
  from myTable t
), expanded_a1 as (
   select a.seq
    ,f.value as val
  from seq_myTable a, 
    lateral flatten(input => a.a1) f
), expanded_a2 as (
   select a.seq
    ,f.value as val
  from seq_myTable a, 
    lateral flatten(input => a.a2) f
)
select coalesce(a.seq,b.seq) as seq, array_agg(coalesce(a.val,b.val)) as vals
from expanded_a1 a
full outer join expanded_a2 b 
    on a.seq = b.seq and a.val = b.val
where (a.seq is null OR b.seq is null)
group by 1;

это дает ответы, но они не отсортированы, для чего вам нужно:

with myTable as (
    SELECT array_construct('a', 'b', 'c', 'd', 'e') as a1
    ,array_construct('a', 'f', 'c', 'g', 'e') as a2
), seq_myTable as (
    SELECT seq8() as seq
    ,t.*
  from myTable t
), expanded_a1 as (
   select a.seq
    ,f.value as val
  from seq_myTable a, 
    lateral flatten(input => a.a1) f
), expanded_a2 as (
   select a.seq
    ,f.value as val
  from seq_myTable a, 
    lateral flatten(input => a.a2) f
)
select array_agg(val) WITHIN GROUP ( order by val) as vals 
from (
  select coalesce(a.seq,b.seq) as seq, coalesce(a.val,b.val) as val
  from expanded_a1 a
  full outer join expanded_a2 b 
      on a.seq = b.seq and a.val = b.val
  where (a.seq is null OR b.seq is null)
)
group by seq;

дает вывод [ "b", "d", "f", "g" ]

0 голосов
/ 31 октября 2019

Я не уверен, что вам нужна последовательность, как в другом ответе. Это работает довольно чисто:

with myTable as (
select array_construct('a', 'b', 'c', 'd', 'e') as a1
    ,array_construct('a', 'f', 'c', 'g', 'e') as a2
)
SELECT array_agg(coalesce(a1.value,a2.value)) WITHIN GROUP (ORDER BY coalesce(a1.value,a2.value)) as newarray
FROM (
  SELECT *
  FROM myTable,
  lateral flatten(input => a1) a1
  ) a1
FULL OUTER JOIN (
  SELECT *
  FROM myTable,
  lateral flatten(input => a2) a2
  ) a2
ON a1.value::varchar = a2.value::varchar
WHERE a1.value IS NULL
   OR a2.value IS NULL
;
...