SQL - 使用窗口和 case 语句展平 table

SQL - Flattening a table using windowing and case statements

第一次提问 -- 我在 SqlServer 2012 中结合案例逻辑和窗口时遇到了一些问题。我需要展平下面显示的数据结构,所以我将 运行 MAX 语句反对这些结果然后。我正在使用 case/when 逻辑为每个 xID 指定一个 'Owner'。我面临的挑战是我一直得到错误的结果,而且我无法确定我做错了什么。

这里是case/when逻辑和table结构。对于 'Owner' 列,我需要评估三个条件并尝试使用 FIRST_VALUE() 到 select 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

第一个 table 显示了我预期的结果,但代码在第二个 table 中生成了值。示例:对于 xID=100,我希望所有者为 grp_Banana,但我的代码为 returns grp_Apple。对于 xID=101,我得到了正确的答案,但是出于错误的原因。窗口函数似乎正在为任何结果集采用第一个 yID。

谢谢,如有任何帮助,我们将不胜感激。另外,我愿意不使用窗口函数,这似乎是正确的方向。

这很棘手,除非您的数据库支持 ignore nulls 参数。您可以使用两个 window 函数来做到这一点:

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

根据@Gordon-Linoff 的建议,我解决了我的问题。这是修改后的代码。看到 Gordon 在 Order By 中使用 case 语句让我意识到为什么我的代码有时会选择错误的值。我把答案归功于他,因为我只是建立在他的方法之上。非常感谢。

, 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'