【问题标题】:Join lookup table on lowest-level/most detailed field value first首先在最低级别/最详细的字段值上加入查找表
【发布时间】:2020-02-18 17:21:32
【问题描述】:

我有两个表,我试图基于 SQL Server 2014 中的单个字段离开联接,但问题是这个单个字段包含一个与出现在不同列中的四个“级别”之一相关的值主表。 SalesOrg 字段也是键的一部分,因为在事务表和查找表中都可以有多个销售组织。

这是主要的事务表:

SalesOrg     PHLevel1    PHLevel2    PHLevel3    PHLevel4    SalesQty
-----------------------------------------------------------------------
AB1          Z000        Y000        X000        V000        20
AB1          Z000        Y000        X000        V001        30
AB1          Z001        Y000        X001        V001        10
AB1          Z001        Y001        X000        V003        45
AB1          Z001        Y001        X000        V004        48
AB1          Z002        Y003        X002        V005        67

这是我尝试加入事务表的查找表:

SalesOrg     PH              PHLevel      SalesRep
--------------------------------------------------
AB1          <null>          0            Mr. Pink
AB1          Z000            1            Mr. White
AB1          Z001            1            Mr. White
AB1          Z001Y000        2            Mr. Orange
AB1          Z001Y001        2            Mr. Orange
AB1          Z001Y001X000    3            Mr. Blonde

所以应该首先匹配“最低”(即最高PHLevel,3),即:

SalesOrg     PHLevel1    PHLevel2    PHLevel3    PHLevel4    SalesQty    SalesRep
---------------------------------------------------------------------------------
AB1          Z000        Y000        X000        V000        20
AB1          Z000        Y000        X000        V001        30
AB1          Z001        Y000        X001        V001        10
AB1          Z001        Y001        X000        V003        45          Mr. Blonde
AB1          Z001        Y001        X000        V004        48          Mr. Blonde
AB1          Z002        Y003        X002        V005        67

然后我们需要匹配尚未使用级别 3 匹配的级别 2:

SalesOrg     PHLevel1    PHLevel2    PHLevel3    PHLevel4    SalesQty    SalesRep
---------------------------------------------------------------------------------
AB1          Z000        Y000        X000        V000        20
AB1          Z000        Y000        X000        V001        30
AB1          Z001        Y000        X001        V001        10          Mr. Orange
AB1          Z001        Y001        X000        V003        45          Mr. Blonde
AB1          Z001        Y001        X000        V004        48          Mr. Blonde
AB1          Z002        Y003        X002        V005        67

然后我们需要匹配尚未使用级别 2 或 3 匹配的级别 1:

SalesOrg     PHLevel1    PHLevel2    PHLevel3    PHLevel4    SalesQty    SalesRep
---------------------------------------------------------------------------------
AB1          Z000        Y000        X000        V000        20          Mr. White
AB1          Z000        Y000        X000        V001        30          Mr. White
AB1          Z001        Y000        X001        V001        10          Mr. Orange
AB1          Z001        Y001        X000        V003        45          Mr. Blonde
AB1          Z001        Y001        X000        V004        48          Mr. Blonde
AB1          Z002        Y003        X002        V005        67

最后,对于任何剩余的项目,我们需要检查级别 0,这是“不匹配”条目的默认值:

SalesOrg     PHLevel1    PHLevel2    PHLevel3    PHLevel4    SalesQty    SalesRep
---------------------------------------------------------------------------------
AB1          Z000        Y000        X000        V000        20          Mr. White
AB1          Z000        Y000        X000        V001        30          Mr. White
AB1          Z001        Y000        X001        V001        10          Mr. Orange
AB1          Z001        Y001        X000        V003        45          Mr. Blonde
AB1          Z001        Y001        X000        V004        48          Mr. Blonde
AB1          Z002        Y003        X002        V005        67          Mr. Pink

如果在事务表中创建连接字段,以便更容易匹配查找表,则没有问题。

我不确定扩展查找表是否有利,以便 PH 字段包含“完全限定”值(即,PH 始终包含 PHLevel1/PHLevel2/@987654334 @/PHLevel4 值,例如 Z001Y000X001V001),但这可能会使查找表变大,然后可能会减慢连接速度(因为事务表可能包含一百万行)。

我不知道如何开始,因为我已经看到其他带有层次结构的示例,但是查找表并不完全是一个层次结构 - 请问在 SQL 中有什么优雅的解决方案吗?

【问题讨论】:

    标签: sql sql-server join


    【解决方案1】:

    当我看到这样的代码时,我有点焦虑,但在您的情况下,它似乎反映了真正的需求,假设您无法更改表的底层结构:

    select      t.*,
                SalesRep = coalesce(l4.SalesRep, l3.SalesRep, l2.SalesRep, l1.SalesRep, l0.SalesRep)
    from        @transactionals t
    left join   @lookup l4 on t.SalesOrg = l4.SalesOrg and l4.PH = t.PHLevel1 + t.PHLevel2 + t.PHLevel3 + t.PHLevel4 
    left join   @lookup l3 on t.SalesOrg = l3.SalesOrg and l3.PH = t.PHLevel1 + t.PHLevel2 + t.PHLevel3
    left join   @lookup l2 on t.SalesOrg = l2.SalesOrg and l2.PH = t.PHLevel1 + t.PHLevel2 
    left join   @lookup l1 on t.SalesOrg = l1.SalesOrg and l1.PH = t.PHLevel1 
    left join   @lookup l0 on t.SalesOrg = l0.SalesOrg and l0.PH is null
    


    经过多一点考虑,我认为另一种策略会奏效。正如您所怀疑的,您可以连接事务表中的级别。然后,您可以根据 like 语句进行匹配。当然,这会让你得到太多的匹配,所以你使用一个窗口函数来找到匹配之间的最大 phLevel。然后查询 phLevel 等于最大值的位置。
    with
    
        leadMatches as (
    
            select      t.*, 
                        l.SalesRep,
                        l.PHLevel,
                        maxPhLevel = max(l.phLevel) over (partition by ap.ph)
            from        @transactionals t
            cross apply (select PH = PHLevel1 + PHLevel2 + PHLevel3 + PHLevel4) ap
            join        @lookup l on t.SalesOrg = l.SalesOrg and ap.ph like isnull(l.ph,'') + '%'
    
        )
    
        select      m.SalesOrg, m.PHLevel1, m.PHLevel2, m.PHLevel3, m.PHLevel4, 
                    m.SalesQty, m.SalesRep
        from        leadMatches m
        where       PHLevel = maxPhLevel
    

    【讨论】:

      【解决方案2】:

      这对apply来说似乎是一个机会:

      select t.*, l.salesrep
      from transactional t outer apply
           (select top (1) l.*
            from lookup l
            where l.ph in (t.PHLevel + t.PHLevel2 + t.PHLevel3, t.PHLevel + t.PHLevel2, t.PHLevel) or
                  l.ph is null
            order by l.phlevel desc
           ) l;
      

      您可以轻松地将PHLevel4 添加到搜索列表中。您的部分问题表明您想要包含它,但它不在详细示例中。

      【讨论】:

        猜你喜欢
        • 2011-05-15
        • 2020-03-22
        • 1970-01-01
        • 1970-01-01
        • 2014-12-11
        • 1970-01-01
        • 2013-11-08
        • 1970-01-01
        • 2013-10-28
        相关资源
        最近更新 更多