我可以在JOIN条件下使用CASE语句吗?

问题描述 投票:99回答:8

以下图像是Microsoft SQL Server 2008 R2系统视图的一部分。从图像中我们可以看出sys.partitionssys.allocation_units之间的关系取决于sys.allocation_units.type的值。所以要将它们连接在一起,我会写一些与此类似的东西:

SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id = p.hobt_id 
               WHEN a.type IN (2)
                   THEN a.container_id = p.partition_id
               END 

但是上面的代码给出了语法错误。我猜这是因为CASE声明。任何人都可以帮忙解释一下吗?


添加错误消息:

消息102,级别15,状态1,行6'='附近的语法不正确。

sql sql-server join case
8个回答
183
投票

CASE表达式从子句的THEN部分返回一个值。你可以这样使用它:

SELECT  * 
FROM    sys.indexes i 
    JOIN sys.partitions p 
        ON i.index_id = p.index_id  
    JOIN sys.allocation_units a 
        ON CASE 
           WHEN a.type IN (1, 3) AND a.container_id = p.hobt_id THEN 1
           WHEN a.type IN (2) AND a.container_id = p.partition_id THEN 1
           ELSE 0
           END = 1

请注意,您需要对返回的值执行某些操作,例如:将它与1.进行比较。您的语句试图返回赋值或测试的相等值,这两者在CASE / THEN子句的上下文中都没有意义。 (如果BOOLEAN是一个数据类型,那么对相等性的测试是有意义的。)


29
投票

相反,您只需加入两个表,并在SELECT子句中返回匹配的数据:

我建议你通过这个链接Conditional Joins in SQL ServerT-SQL Case Statement in a JOIN ON Clause

EG

    SELECT  *
FROM    sys.indexes i
        JOIN sys.partitions p
            ON i.index_id = p.index_id 
        JOIN sys.allocation_units a
            ON a.container_id =
            CASE
               WHEN a.type IN (1, 3)
                   THEN  p.hobt_id 
               WHEN a.type IN (2)
                   THEN p.partition_id
               END 

编辑:根据评论。

你不能像你一样指定连接条件。检查上面没有错误的查询。我已经取出了公共列,并且将根据条件评估右列值。


16
投票

试试这个:

...JOIN sys.allocation_units a ON 
  (a.type=2 AND a.container_id = p.partition_id)
  OR (a.type IN (1, 3) AND a.container_id = p.hobt_id)

7
投票

我认为你需要两个案例陈述:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON 
        -- left side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN a.container_id
               WHEN a.type IN (2)
                   THEN a.container_id
            END 
        = 
        -- right side of join on statement
            CASE
               WHEN a.type IN (1, 3)
                   THEN p.hobt_id
               WHEN a.type IN (2)
                   THEN p.partition_id
            END             

这是因为:

  • CASE语句在END返回单个值
  • ON语句比较两个值
  • 您的CASE语句正在CASE语句中进行比较。我猜想如果你把你的CASE语句放在你的SELECT中你会得到一个布尔值'1'或'0'来表示CASE语句是否被评估为True或False

1
投票

这看起来不错

https://bytes.com/topic/sql-server/answers/881862-joining-different-tables-based-condition

FROM YourMainTable
LEFT JOIN AirportCity DepCity ON @TravelType = 'A' and DepFrom =  DepCity.Code
LEFT JOIN AirportCity DepCity ON @TravelType = 'B' and SomeOtherColumn = SomeOtherColumnFromSomeOtherTable

1
投票

我拿了你的例子并编辑了它:

SELECT  *
FROM    sys.indexes i
    JOIN sys.partitions p
        ON i.index_id = p.index_id 
    JOIN sys.allocation_units a
        ON CASE
           WHEN a.type IN (1, 3)
               THEN p.hobt_id 
           WHEN a.type IN (2)
               THEN p.partition_id
           ELSE NULL
           END = a.container_id

0
投票

在这里,我比较了两种不同结果集的差异。希望这可能会有所帮助。

SELECT main.ColumnName, compare.Value PreviousValue,  main.Value CurrentValue
FROM 
(
    SELECT 'Name' AS ColumnName, 'John' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'jh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, NULL as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) main
INNER JOIN
(
    SELECT 'Name' AS ColumnName, 'Rahul' as Value UNION ALL
    SELECT 'UserName' AS ColumnName, 'rh001' as Value UNION ALL
    SELECT 'Department' AS ColumnName, 'HR' as Value UNION ALL
    SELECT 'Phone' AS ColumnName, '01722112233' as Value UNION ALL
    SELECT 'DOB' AS ColumnName, '1993-01-01' as Value UNION ALL
    SELECT 'CreateDate' AS ColumnName, '2017-01-01' as Value UNION ALL
    SELECT 'IsActive' AS ColumnName, '1' as Value
) compare
ON main.ColumnName = compare.ColumnName AND
CASE 
    WHEN main.Value IS NULL AND compare.Value IS NULL THEN 0
    WHEN main.Value IS NULL AND compare.Value IS NOT NULL THEN 1
    WHEN main.Value IS NOT NULL AND compare.Value IS NULL THEN 1
    WHEN main.Value <> compare.Value THEN 1
END = 1 

0
投票

拿了DonkeyKong的例子。

问题是我需要使用声明的变量。这允许说明您需要比较的左侧和右侧。这是为了支持SSRS报告,其中必须根据用户的选择链接不同的字段。

初始案例根据选择设置字段选择,然后我可以设置我需要匹配的字段用于连接。

如果需要变量来从不同的字段中进行选择,则可以为右侧添加第二个case语句

LEFT OUTER JOIN Dashboard_Group_Level_Matching ON
       case
         when @Level  = 'lvl1' then  cw.Lvl1
         when @Level  = 'lvl2' then  cw.Lvl2
         when @Level  = 'lvl3' then  cw.Lvl3
       end
    = Dashboard_Group_Level_Matching.Dashboard_Level_Name
© www.soinside.com 2019 - 2024. All rights reserved.