带有条件 CASE 语句的 SQL LEFT JOIN

Posted

技术标签:

【中文标题】带有条件 CASE 语句的 SQL LEFT JOIN【英文标题】:SQL LEFT JOIN with conditional CASE statements 【发布时间】:2016-01-11 07:24:58 【问题描述】:

希望这是一个快速的

SELECT *
FROM T
left JOIN J ON 
  CASE
    WHEN condition1 THEN 1 --prefer this option even if CASE2 has a value
    WHEN condition2 THEN 2
    ELSE 0
  END = 1 (edit: but if 1 does not satisfy, then join on 2)

两种情况都返回结果,但我希望 THEN 1 取代 THEN 2 并成为查找优先级

我可以让 SQL 执行诸如加入 max(CASE) 之类的操作吗?

基本上我试图从 Excel 复制嵌套的 INDEX/MATCH

编辑:我听到的是,案例应该在第一个返回的 TRUE 处停止,但是当我测试时它的行为不是那样

SELECT *
FROM T
left JOIN J ON 
  CASE
    WHEN condition1 THEN 1 --prefer this option even if CASE2 has a value
    WHEN condition2 THEN 1
    ELSE 0
  END = 1

它似乎有时更喜欢 2nd THEN 1,但并非总是如此……有什么我遗漏的东西会导致这种行为吗?

【问题讨论】:

案例表达式,而不是案例陈述...... 将使用第一个真正的条件。 我认为第一个 TRUE 也会被使用,但是当我测试它时,情况并非如此。 (当我测试它时,两者都是 THEN 1)我为这个例子添加了 THEN 2 该语句不会捕获 col2 匹配而 col1 不匹配的情况。请添加数据示例以及预期的结果集。 也许您的联接只需要使用OR,但您输出的列描述了按优先级应用的匹配项。 【参考方案1】:

哪个条件导致行在连接中匹配并不重要。在连接中使用case 表达式是有正当理由的,但我认为您只想or 您的条件,然后使用case 表达式输出匹配的排名原因。

SELECT *, CASE WHEN <condition1> THEN 1 WHEN <condition2> THEN 2 END as match_code
FROM T LEFT OUTER JOIN J ON <condition1> or <condition2>

关于 Excel 中的“嵌套索引/匹配”,我不知道该怎么做。如果我在上面的错误轨道上,那么也许您正在寻找嵌套的 case 表达式?

现在,如果您的条件将在不同的行中匹配并且您只想保留一个,那么...

WITH matches AS (
    SELECT *, CASE WHEN <condition1> THEN 1 WHEN <condition2> THEN 2 END AS match_code
    FROM T LEFT OUTER JOIN J ON <condition1> OR <condition2>
), ranked as (
    SELECT *, MIN(match_code) OVER (PARTITION BY ???) AS keeper
    FROM matches
)
SELECT ...
FROM ranked
WHERE match_code = keeper

【讨论】:

我认为这是最好的方法。选择 CASE 和 CTE【参考方案2】:

好吧,你的 CASE 语句中总是可以有几个条件:

  SELECT *
FROM T

left JOIN J ON 
  CASE
    WHEN condition1 THEN 1 --prefer this option even if CASE2 has a value
    WHEN condition2 And !condition1 THEN 2
  ELSE 0
END = 1

--已更新-- 如果您的两个条件都需要匹配,但条件 1 是可选的,那么您也可以尝试以下语句:

  SELECT *
FROM T  
left JOIN J ON 
  CASE
    WHEN condition1 And condition2 THEN 1 --Both conditions match
    WHEN condition2 THEN 2 -- condition1 has no match
  ELSE 0
END = 1

【讨论】:

但正如@Amir 在他的评论中回答的那样,如果条件 1 匹配,那么 SQL Server 将不匹配任何其他条件,并且会通过选择第一个选项来停止。 我想我想做的是告诉 SQL 我想在两种情况下都尝试 JOIN 但返回结果为 1,如果 1 没有结果,则转到 2 嗯,实际上就是这样! :) 看看:msdn.microsoft.com/en-us/library/ms181765.aspx - CASE 语句按顺序评估其条件,并在满足条件的第一个条件处停止。 所以如果.. 我设置了两个条件 THEN 1.. 它应该在第一个满足的条件处停止,而不是进一步进入 CASE.. 对吗? 看,你有两个 WHEN 选项的 CASE,不管有多少条件。对于指定的所有条件都匹配的任何 WHEN,处理该 WHEN 并且 SQL Server 将停止进一步处理。如果不存在所有条件都匹配的 WHEN 条件,则服务器使用 ELSE 语句进行处理。如果没有 ELSE 语句,则最终值为 NULL。【参考方案3】:

您可以分两步使用With 声明:

 With first_join as  
    (SELECT *
    FROM T
    left JOIN J ON condition1)
      select * from first_join 
    join J On case when Name_of_2nd_condition is null 
       then     condition2 
      ELSE null end

【讨论】:

【参考方案4】:

您可以使用 CROSS APPLY /OUTER APPLY 运算符:https://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/

SELECT *
FROM T
    OUTER APPLY (SELECT TOP 1 *
                 FROM J
                 WHERE condition1 OR condition2
                 ORDER BY order) J

【讨论】:

这种工作方式是一种变通方法。不是我要找的 通过这种方式,您可能会提高您的表现,但我同意,这是一种解决方法。 。看起来我可以按结果集对其进行排序,但我无法告诉它更喜欢哪个条件 您也可以在 SELECT 语句中创建 CASE WHEN。让我知道条件,使查询更相关 这里是实际代码如果有帮助的话,我不知道如何在评论区格式化left JOIN [CC_Note_Log].[dbo].[Desk_Mapping] DON CASE WHEN S.tag1=D.Location and S.tag5=D.Line THEN 1WHEN S.Location2ID=D.TwoID and S.tag5=D.Line THEN 1WHEN S.tag1='LKW' and S.tag5=D.Line THEN 1ELSE 0@ 987654330@

以上是关于带有条件 CASE 语句的 SQL LEFT JOIN的主要内容,如果未能解决你的问题,请参考以下文章

没有值时带有 CASE 的 SQL 语句

PL/SQL 中 CASE 语句中的堆栈条件

带有“case”的sql语句的奇怪行为

SQL条件语句(IF, CASE WHEN, IF NULL)

sql语句借助case when实现自动拼装where条件

SQL 中 where 条件中 in 后面 加 CASE WHEN 语句 报错