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

时间:2012-04-21 06:33:34

标签: sql sql-server join case

以下图像是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声明。 任何人都可以帮忙解释一下吗?

谢谢!


添加错误消息:

  

Msg 102,Level 15,State 1,Line 6'='附近的语法不正确。

this is the image

10 个答案:

答案 0 :(得分:178)

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是一种数据类型,那么相等性测试就有意义了。)

答案 1 :(得分:29)

  

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

我建议您浏览此链接Conditional Joins in SQL ServerT-SQL Case Statement in a JOIN ON Clause

e.g。

    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 

编辑:根据评论。

  

您不能像正在做的那样指定连接条件。检查   上面的查询没有错误。我已经把共同栏目拿出来了   并且将根据条件评估正确的列值。

答案 2 :(得分: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)

答案 3 :(得分:4)

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

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

答案 4 :(得分:2)

是的,可以。这是一个例子。

SELECT a.*
FROM TableA a
LEFT OUTER JOIN TableB j1 ON  (CASE WHEN LEN(COALESCE(a.NoBatiment, '')) = 3 
                                THEN RTRIM(a.NoBatiment) + '0' 
                                ELSE a.NoBatiment END ) = j1.ColumnName 

答案 5 :(得分: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

答案 6 :(得分: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

答案 7 :(得分: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 

答案 8 :(得分: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

答案 9 :(得分:0)

根据条件至少有两种加入方式。一个比另一个更快:

declare @loopZaKosovnice int = 1
select * 
from tHE_MoveItem mi 
left join tHE_SetProdSt st on st.acIdent = mi.acIdent

-- slow
--join the_setitem si on si.acident = case when @loopZaKosovnice = 0 then mi.acident else st.acIdentChild end 

-- two times as fast
left join the_setitem si1 on @loopZaKosovnice = 0 and si1.acident = mi.acident
left join the_setitem si2 on @loopZaKosovnice = 1 and si2.acident = st.acIdentChild
join the_setitem si on si.acident = isnull (si1.acident, si2.acIdent)