как обеспечить детерминированный c результат запроса, который использует mode () в снежинке - PullRequest
2 голосов
/ 13 января 2020

Я использую снежинку и хочу использовать несколько выражений mode() в одном операторе выбора. Так это выглядит так:

SELECT
x,
y,
mode(col1),
mode(col2),
...
mode(col15)
FROM table
GROUP BY x, y

Моя проблема в том, что он выдает недетерминированный вывод c в случае связей. Документация не объясняет, как именно разрешаются связи. Он говорит только:

Если для наиболее часто встречающегося значения в ie (два или более значений встречаются так же часто, как и другие, и чаще, чем любое другое значение), MODE возвращает одно из этих значений. значения.

https://docs.snowflake.net/manuals/sql-reference/functions/mode.html Мне нужен обходной путь, чтобы получить эквивалент mode(), который всегда приведет к определенному выводу c. Что-то вроде: используйте mode(), но в случае порядка ie по некоторому столбцу и выберите первое значение.

Я не предоставляю пример для репликации недетерминированных c результат, потому что кажется, что это происходит только с большими наборами данных или сложными запросами.

Ответы [ 3 ]

2 голосов
/ 13 января 2020

Это отвечает на исходную версию вопроса.

Один из методов заключается в использовании подзапроса с функциями агрегирования и окна:

select col, val as mode
from (select col, val, count(*),
             row_number() over (partition by col order by count(*) desc, val) as seqnum
      from t
      group by col, val
     ) cv
where seqnum = 1;

Второй ключ в order by добавляет детерминизм в случае связей.

1 голос
/ 14 января 2020

, поэтому режим, похоже, предпочитает первое значение, которое он видит в ie выключателе.

with data as (
select x, col1, col2, col3 from values (1, 1, 1, 3), (1, 1, 2,3), (1, 2, 2,3)
    ,(4, 1, 20, 30), (4, 1, 2, 3), (4, 2, 2, 30), (4,2,20,3) v(x,col1,col2,col3)
)
select x
    ,mode(col1)
    ,mode(col2)
    ,mode(col3)
from data 
group by 1
order by 1;

, поменяв местами первое значение пары 2/20 или 3/30, показывает это.

поэтому создайте шаблон, пытаясь решить эту проблему в одном выражении:

with data as (
select x, col1, col2, col3 from values (1, 1, 1, 3), (1, 1, 2,3), (1, 2, 2,3)
    ,(4, 1, 20, 30), (4, 1, 2, 3), (4, 2, 2, 30), (4,2,20,3) v(x,col1,col2,col3)
)
select x
    ,col1
    ,col2
    ,col3
    ,count(col1)over(partition by x,col1) c_col1
    ,count(col2)over(partition by x,col2) c_col2
    ,count(col3)over(partition by x,col3) c_col3
from data ;

предоставляет себя:

with data as (
select x, col1, col2, col3 from values (1, 1, 1, 3), (1, 1, 2,3), (1, 2, 2,3)
    ,(4, 1, 20, 30), (4, 1, 2, 3), (4, 2, 2, 30), (4,2,20,3) v(x,col1,col2,col3)
)
select x
    ,col1
    ,col2
    ,col3 
    ,row_number() over (partition by x order by c_col1 desc, col1) as r1
    ,row_number() over (partition by x order by c_col2 desc, col2) as r2
    ,row_number() over (partition by x order by c_col3 desc, col3) as r3
from (
  select x
      ,col1
      ,col2
      ,col3
      ,count(col1)over(partition by x,col1) c_col1
      ,count(col2)over(partition by x,col2) c_col2
      ,count(col3)over(partition by x,col3) c_col3
  from data 
)
order by 1;

с таким результатом:

X   COL1    COL2    COL3    R1  R2  R3
1   1   2   3   2   1   1
1   2   2   3   3   2   2
1   1   1   3   1   3   3
4   1   2   3   2   1   1
4   2   20  3   4   4   2
4   2   2   30  3   2   3
4   1   20  30  1   3   4

вы не можете использовать logi c, например

QUALIFY row_number() over (partition by x order by c_col1 desc, col1) = 1
  AND row_number() over (partition by x order by c_col2 desc, col2) = 1
  AND row_number() over (partition by x order by c_col3 desc, col3 desc) = 1

, чтобы выбрать лучшее, так как лучшие строки для каждого столбца не выровнены.

, что приводит к CTE (или подзапросу) для каждый столбец, в основном по образцу, который показал Горндон.

with data as (
select x, col1, col2, col3 from values (1, 1, 1, 3), (1, 1, 2,3), (1, 2, 2,3)
    ,(4, 1, 20, 30), (4, 1, 2, 3), (4, 2, 2, 30), (4,2,20,3) v(x,col1,col2,col3)
),col1_m as (
    select x, col1, count(*) as c 
    from data 
    group by 1,2
    QUALIFY row_number() over (partition by x order by c desc, col1) = 1
),col2_m as (
    select x, col2, count(*) as c 
    from data 
    group by 1,2
    QUALIFY row_number() over (partition by x order by c desc, col2) = 1
),col3_m as (
    select x, col3, count(*) as c 
    from data 
    group by 1,2
    QUALIFY row_number() over (partition by x order by c desc, col3) = 1
), base as (
select distinct x from data
)
select b.x
    ,c1.col1
    ,c2.col2
    ,c3.col3
from base as b
left join col1_m as c1 on b.x = c1.x
left join col2_m as c2 on b.x = c2.x
left join col3_m as c3 on b.x = c3.x
order by 1;

, который дает ожидаемые результаты

X   COL1    COL2    COL3
1   1   2   3
4   1   2   3

, но вам нужно будет расширить X, чтобы он был набором вещей ( х, у, ..) что вы заботитесь о c.

0 голосов
/ 14 января 2020

Это должно вызвать детерминированность c sort.

SELECT 
row_number() over (partition by t.COL_X order by t.COL1, t.COL2, t.COL3, t.COL4, t.COL5, t.COL6) as rn, 
t.* 

FROM TABLE t
WHERE t.CONDITION = X 

QUALIFY row_number() over (partition by t.COL_X order by t.COL1, t.COL2, t.COL3, t.COL4, t.COL5, t.COL6) = 1
ORDER BY t.COL1, t.COL2, t.COL3, t.COL4, t.COL5, rn
...