包含一个联接条件的联接的SQL

包含一个联接条件的联接的SQL,sql,sql-server,tsql,join,Sql,Sql Server,Tsql,Join,我需要在两个表之间进行左连接。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) 最后一个

我需要在两个表之间进行左连接。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)
最后一个连接条件,括号中的部分,就是我遇到的问题

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

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

我唯一能想到的就是执行两次查询,一次使用FundID=1,然后使用FundID=99。然后使用set运算符返回第一个查询中的所有记录,并仅返回第一个查询中不存在的第二个查询中的记录。代码将不美观,而且似乎也不高效

提前谢谢你的想法


马吕斯

您可以将查询更改为

AND b.FundID IN (1,99)


如果我正确理解你的要求,这应该会给你你想要的

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

这是迄今为止我收到的最好的解决方案。感谢@HABO,请参见我问题的评论部分

添加一列以创建按ItemType和ItemCode分区并按FundId排序的行号,然后仅为后代使用行号为1的结果:

-- 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;

那是行不通的。规则是在FundID=1时加入,如果不起作用,则仅在FundID=99时加入。可能存在FundID 1和99的匹配记录-在这种情况下,我只需要返回匹配记录,其中FundID=1而不是99。如果FundID=1,则不能是99。你能添加一些输入和输出数据吗?更清楚。OP的意思是,如果前三个条件失败,那么只需要FundID=99就可以进行匹配。您的回答与此不一致。OP需要确认此要求。我不认为它不需要另外两个条件添加一个列来创建一个行号,该行号在ItemType和ItemCode上划分并按FundId排序,然后只使用行号为1的结果?当使用b.FundId=99时,您是否仍然需要ItemCode和ItemType上的条件?@Squirrel是,当使用b.FundId=99时,我仍然需要ItemCode和ItemType@Marius那么TriV给出的答案应该是有效的,这也意味着你问题中的语言不清楚。在199中使用b.fundID很乐意帮忙,很抱歉我没有时间写完整的答案。您应该编辑您的答案,以包括您创建的查询,以便将来偶然发现您的问题的其他人受益。收集一些选票。
-- 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;