SQL - Сглаживание таблицы с использованием окон и операторов case - PullRequest
4 голосов
/ 25 марта 2019

Первый раз, когда задаю вопрос - у меня возникли некоторые проблемы при объединении логики наблюдений и управления окнами в SqlServer 2012. Мне нужно сгладить структуру данных, показанную ниже, поэтому впоследствии я буду запускать операторы MAX для этих результатов. Я использую логику case / when, чтобы указать «владельца» для каждого xID. Моя проблема в том, что я последовательно получаю неправильные результаты, и я не смог определить, что я делаю неправильно.

Вот случай / когда логика и структура таблицы. Для столбца «Владелец» мне нужно оценить три условия, и я пытался использовать FIRST_VALUE () для выбора выходных данных оператора case. Логика в выражении case работает правильно, но когда я пытаюсь применить значение к каждому из xID с помощью функции управления окнами, он возвращает неправильное значение.

FIRST_VALUE(case
when [partnerType] = 'Giver' and [partnerAgree] = 'True' then [partnerGroup]
when [partnerType] = 'Impacted' and [partnerAgree] = 'True' then [partnerGroup]
when [Stakeholder No#] = 1 and [partnerAgree] <> 'True' then [partnerGroup]
else Null end) over (partition by [xID] order by [yID])
as 'Owner'

Desired Results --------------------------

|xID|yID| Owner     |partnerType| partnergrp|partnerAgree
|100|  1| grp_Banana|Taker      |grp_Apple  |TRUE
|100|  2| grp_Banana|Giver      |grp_Banana |TRUE
|100|  3| grp_Banana|Taker      |grp_Banana |FALSE
|101|  1| grp_Carrot|Taker      |grp_Carrot |TRUE
|101|  2| grp_Carrot|Giver      |grp_Danish |FALSE
|101|  3| grp_Carrot|Taker      |grp_Banana |TRUE
|101|  4| grp_Carrot|Taker      |grp_Danish |FALSE

Results I'm getting --------------------------

|xID|yID| Owner     |partnerType| partnergrp|partnerAgree
|100|  1| grp_Apple |Taker      |grp_Apple  |TRUE
|100|  2| grp_Apple |Giver      |grp_Banana |TRUE
|100|  3| grp_Apple |Taker      |grp_Banana |FALSE
|101|  1| grp_Carrot|Taker      |grp_Carrot |TRUE
|101|  2| grp_Carrot|Giver      |grp_Danish |FALSE
|101|  3| grp_Carrot|Taker      |grp_Banana |TRUE
|101|  4| grp_Carrot|Taker      |grp_Danish |FALSE

Первая таблица показывает результаты, как я и ожидал, но код выдает значения во второй таблице. Пример: для xID = 100 я бы ожидал, что владельцем будет grp_Banana, но мой код возвращает grp_Apple. Для xID = 101 я получаю правильный ответ, но по неправильной причине. Кажется, что оконная функция берет первый yID для любого набора результатов.

Спасибо, любая помощь приветствуется. Кроме того, я открыт для того, чтобы не использовать оконную функцию, это просто кажется правильным направлением.

Ответы [ 2 ]

2 голосов
/ 25 марта 2019

Это сложно, если ваша база данных не поддерживает аргумент ignore null s. Вы можете сделать это с помощью двух оконных функций:

max(case when yid = yid_special then partnerGroup end) over (partition by xid) as Owner
from (select . . . ,
             min(case when partnerType = 'Giver' and [partnerAgree] = 'True' then yid
                      when partnerType = 'Impacted' and [partnerAgree] = 'True' then yid
                      when [Stakeholder No#] = 1 and [partnerAgree] <> 'True' then yid
                 end) over (partition by xid) as yid_special

Вы также можете написать это, используя first_value():

first_value(partnerGroup) over
    (partition by xid
     order by (case when partnerType = 'Giver' and [partnerAgree] = 'True' then yid
                    when partnerType = 'Impacted' and [partnerAgree] = 'True' then yid
                    when [Stakeholder No#] = 1 and [partnerAgree] <> 'True' then yid
                    else 999999
                end) 
    ) as owner
0 голосов
/ 26 марта 2019

Используя предложение @ Gordon-Linoff, я смог решить свою проблему.Вот модифицированный код.Увидев использование Гордоном оператора case в Order By, я понял, почему мой код иногда выбирал неправильные значения.Я доверяю ему ответ, так как я только построил на его подходе.Очень ценится.

, FIRST_VALUE(
case
when [partnerType] = 'Remediator' and [partnerAgree] = 'True' then [partnerGroup]
when [partnerType] = 'Impacted' and [partnerAgree] = 'True' then [partnerGroup]
when [yID] = 1 and [partnerAgree] <> 'True' then [partnerGroup]
else [partnerGroup] end) 
over 
(partition by [Incident ID] order by
case 
when [partnerType] = 'Remediator' and [partnerAgree] = 'True' then 1
when [partnerType] = 'Impacted' and [partnerAgree] = 'True' then 2
when [yID] = 1 and [partnerAgree] <> 'True' then 3   
else 100
end
)
as 'Owner'
...