Условная группа по с оконной функцией в запросе Snowflake - PullRequest
1 голос
/ 28 мая 2020

У меня есть таблица в Snowflake в следующем формате:

create temp_test(name string, split string, value int)

insert into temp_test
values ('A','a', 100), ('A','b', 200), ('A','c',300), ('A', 'd', 400), ('A', 'e',500), ('B', 'a', 1000), ('B','b', 2000), ('B','c', 3000), ('B', 'd',4000), ('B','e', 5000)

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

select name, split, value,
row_number() over (PARTITION BY (name) order by value desc) as row_num 
from temp_test
qualify row_num <= 2

Что дает мне следующий набор результатов:

NAME    SPLIT   VALUE   ROW_NUM
A       e       500     1
A       d       400     2
B       e       5000    1
B       d       4000    2

Теперь мне нужно суммировать значения, отличные от Top 2, и поместить их в другой Split с именем «Others ", например:

NAME    SPLIT   VALUE   
A       e       500     
A       d       400     
A       Others  600        
B       e       5000    
B       d       4000
B       Others  6000     

Как это сделать в запросе Snowflake или SQL в целом?

Ответы [ 2 ]

1 голос
/ 28 мая 2020
with data as (
    select name, split, value,
        row_number() over (partition by (name) order by value desc) as row_num 
    from temp_test
)
select
    name,
    case when row_num <= 2 then split else 'Others' end as split,
    sum(value) as value
from data
group by name, case when row_num <= 2 then row_num else 3 end
0 голосов
/ 29 мая 2020

Ответ Shawnt00 хорош, но для записи в Snowflake это можно написать проще:

Во-первых, группа в конце может ссылаться на результаты по индексу или имени:

GROUP BY 1,2

или

GROUP BY name, split

также, поскольку CASE имеет слишком много ветвей, можно использовать IFF и, похоже, вы используете CTE для добавления row_number, который вы можете sh IFF в CTE также

WITH data AS (
    SELECT name, value,
        ROW_NUMBER() OVER (PARTITION BY name ORDER BY value DESC) AS row_num,
        IFF(row_num < 3, split, 'Others') as n_split
    FROM VALUES ('A','a', 100), ('A','b', 200), ('A','c',300), ('A', 'd', 400), 
                ('A', 'e',500), ('B', 'a', 1000), ('B','b', 2000), ('B','c', 3000), 
                ('B', 'd',4000), ('B','e', 5000) 
    v(name, split, value)
)   
SELECT
    name,
    n_split,
    SUM(value) AS value
FROM data
GROUP BY name, n_split;

и, если вы очень любите маленькие SQL pu sh, НОМЕР СТРОКИ в IFF:

WITH data AS (
    SELECT name, value,
        IFF(ROW_NUMBER() OVER (PARTITION BY name ORDER BY value DESC) < 3, split, 'Others') as n_split
    FROM VALUES ('A','a', 100), ('A','b', 200), ('A','c',300), ('A', 'd', 400), 
                ('A', 'e',500), ('B', 'a', 1000), ('B','b', 2000), ('B','c', 3000), 
                ('B', 'd',4000), ('B','e', 5000) 
    v(name, split, value)
)   
SELECT
    name,
    n_split AS split,
    SUM(value) AS value
FROM data
GROUP BY name, n_split;

дает:

NAME    SPLIT   VALUE
A       e       500
A       d       400
A       Others  600
B       e       5000
B       d       4000
B       Others  6000
...