【问题标题】:SQL for a Join that contains a condition within one of the join conditions包含一个连接条件中的条件的连接的 SQL
【发布时间】:2017-04-06 03:21:11
【问题描述】:

我需要在两个表之间进行左连接。 TableA 是事务表,而 TableB 包含参考数据。我加入的逻辑规则如下:

SELECT *
FROM
    TableA a
    LEFT JOIN TableB b
        ON a.ItemCode = b.ItemCode
        AND a.ItemType = b.ItemType
        AND b.FundID = 1 (but if no match found use b.FundID = 99)

最后一个连接条件,括号中的部分,是我遇到的问题。

编辑:一些澄清 - 如果在 ItemCodeItemTypeFundID = 1 上找不到匹配项,那么我想加入 ItemCodeItemTypeFundID = 99。此外,TableB 可能有两条记录在ItemCodeItemType 上都匹配,一条记录具有FundID = 1,第二条记录具有FundID = 2。在那种情况下,我只想要FundID = 1 的记录。

编写此查询的最有效方法是什么?

我唯一能想到的就是执行两次查询,一次是 FundID = 1,然后是 FundID = 99。然后使用集合运算符返回第一个查询的所有记录,只返回第二个查询的记录第一个中不存在的查询。代码不会很漂亮,而且看起来效率也不高。

提前感谢您的想法。

马吕斯

【问题讨论】:

  • 添加一列以创建Row_Number() 分区ItemTypeItemCode 并按FundId 排序,然后仅使用行号为1 的结果?
  • 在使用b.FundID = 99时,还需要ItemCode & Itemtype上的条件吗?
  • @Squirrel 是的,当使用b.FundID = 99 时,我仍然需要ItemCodeItemType 上的条件
  • @Marius 那么TriV给出的答案应该可以,这也意味着您问题中的语言不清楚。
  • 使用b.fundID IN (1, 99)

标签: sql sql-server tsql join


【解决方案1】:

如果我确实正确理解了您的要求,这应该可以满足您的需求

SELECT *
FROM
    TableA a
    OUTER APPLY
    (
        SELECT TOP 1 *
        FROM   TableB b
        WHERE a.ItemCode = b.ItemCode
        AND  a.ItemType = b.ItemType
        AND   b.FundID IN (1, 99)
        ORDER BY b.FundID
    ) b

【讨论】:

    【解决方案2】:

    您可以将查询更改为

    AND b.FundID IN (1,99)
    

    AND (b.FundID = 1 or b.FundID = 99)
    

    【讨论】:

    • 那行不通。规则是在 FundID = 1 上加入,如果这不起作用,则仅在 FundID = 99 上加入。 FundID 1 和 99 可能都有匹配记录 - 在这种情况下,我只需要带回 FundID = 1 而不是 99 的匹配记录。
    • 如果 FundID = 1 则不可能是 99。能不能加点输入输出数据,这样更清楚。
    • OP 说如果前三个条件失败,那么 only FundID = 99 需要进行匹配。您的回答不同意这一点。
    • OP需要确认这个要求。我认为不需要另外两个条件
    【解决方案3】:

    这是迄今为止我收到的最好的解决方案。感谢@HABO(请参阅我问题的 cmets 部分)。

    添加一列以创建在ItemTypeItemCode 上分区并按FundId 排序的Row_Number(),然后仅使用行号为1 的结果

    【讨论】:

    • 很高兴为您提供帮助,对不起,我没有时间写一个完整的答案。您应该编辑您的答案以包含您创建的查询,以便将来偶然发现您的问题的其他人受益。并收集一些赞成票。
    【解决方案4】:

    为了后代:

    -- Sample data.
    declare @TableA as Table ( AId Int Identity, ItemCode VarChar(20), ItemType VarChar(20) );
    declare @TableB as Table ( BId Int Identity, ItemCode VarChar(20), ItemType VarChar(20), FundId Int );
    
    insert into @TableA ( ItemCode, ItemType ) values
      ( 'Nemo', 'Fish' ), ( 'Blinky', 'Fish' ), ( 'Muddy Mudskipper', 'Fish' ),
      ( 'Hammer', 'Tool' ), ( 'Screwdriver', 'Tool' ), ( 'Politician', 'Tool' ),
      ( 'Grape Nehi', 'Beverage' ), ( 'Screwdriver', 'Beverage' );
    insert into @TableB ( ItemCode, ItemType, FundId ) values
      ( 'Blinky', 'Fish', 1 ), ( 'Muddy Mudskipper', 'Fish', 2 ),
      ( 'Hammer', 'Tool', 1 ), ( 'Screwdriver', 'Tool', 99 ),
      ( 'Politician', 'Tool', 1 ), ( 'Politician', 'Tool', 99 ),
      ( 'Grape Nehi', 'Beverage', 42 ), ( 'Screwdriver', 'Beverage', 1 );
    select * from @TableA;
    select * from @TableB;
    
    -- Do the deed.
    with JoinWithRanking as (
      select A.AId, A.ItemCode, A.ItemType, B.BId, B.FundId,
        Row_Number() over ( partition by A.ItemCode, A.ItemType order by B.FundId ) as RN
        from @TableA as A left outer join
          @TableB as B on B.ItemCode = A.ItemCode and B.ItemType = A.ItemType and
            B.FundId in ( 1, 99 )
      )
      select AId, ItemCode, ItemType, BId, FundId
        from JoinWithRanking
        where RN = 1;
    

    【讨论】:

      猜你喜欢
      • 2014-11-17
      • 2014-12-31
      • 2013-05-18
      • 2014-12-25
      • 2011-03-29
      • 2023-04-10
      • 1970-01-01
      相关资源
      最近更新 更多