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


140

下图是Microsoft SQL Server 2008 R2系统视图的一部分。从图像中我们可以看到sys.partitions和之间的关系sys.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行'='附近的语法不正确。

这是图像


36
您使用什么软件制作了这张漂亮的数据库图?
LearnByReading

2
您是否曾经使用@LearnByReading找出使用了哪个软件?
User632716 '18

1
@ User632716不幸的是没有!
LearnByReading

2
@ User632716虽然我真的认为这是MySQL Workbench。但我从未收到回应
LearnByReading

@LearnByReading我不知道。它由Microsoft提供。
只是一个学习者,

Answers:


222

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是数据类型,则对相等性的测试将是有意义的。)


@HABO谢谢,这对我有用...但是问题是当我这样做时,情况会有所下降...请告诉我如何打破它?
Sagar Tandel 2013年

1
@SagarTandel-对不起,我不理解“摔倒”和“如何摔倒”。您能否澄清您的评论?(最近在Saba潜水中浮出水面。可能是Nitrox。)
HABO

它检查所有我不想要的条件。我希望它在符合条件时退出案件。
萨加尔·坦德尔

3
@SagarTandel-来自MSDN:“ CASE语句按顺序评估其条件,并以满足条件的第一个条件停止。” 如果您想要所有不符合任何明确说明的条件的联接行,只需将尾端从更改= 1= 0,但我认为您不会喜欢结果。
HABO

当a.type IN(1,3)和a.container_id = p.hobt_id THEN 1时,在sys.allocation_units联接的情况下当a.type IN(2)和a.container_id = p.partition_id THEN 1时ELSE 0 END = 1您能否在解决方案的上面的Entity Framework中编写它
r.hamd

36

取而代之的是,您只需将JOIN连接到两个表,然后在SELECT子句中,从匹配的表中返回数据:

我建议您通过此链接通过JOIN ON子句中的SQL ServerT-SQL Case语句中的条件连接

例如

    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 

编辑:根据评论。

您无法在执行操作时指定连接条件。.检查上面没有错误的查询。我已经取出了通用列,并且将根据条件评估正确的列值。


1
什么conditional join意思 每个联接(不包括交叉)都是有条件的。这种情况与其他情况有何不同?您的样本具有带条件的内部联接,并且OPs查询具有带条件的联接。
zerkms 2012年

@zerkms:我同意,这听起来令人困惑。我相信,在这种情况下,条件连接意味着条件取决于另一条件的连接。
舍甫琴科中号

@Andriy M:有什么理由想到另一个琐碎的条件OR
zerkms 2012年

@zerkms:嗯,是的,因为听起来令人困惑。:)但是我相信您的意思是要问是否有任何理由考虑另一个术语,在这种情况下我不能确定。如果您出于我的原因而问,那么,我想我只是受不了了。:)如何在其他条件下进行联接?恐怕我不太擅长造币。但是请注意,从概念上讲,这与“条件条件”有关,而不与“带有条件的条件”有关OR。使用OR仅仅是实现它的一种方式。
舍甫琴科中号

@Andriy M:好的。但就我个人而言,我仍然不知道为琐碎的条件使用1 OR和2 ANDs或1 命名的理由CASE。这是一个例行查询,没有其他区别。
zerkms 2012年

17

试试这个:

...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)

即使可行,问题中的查询看起来也很有效。因此,仍然没有解释OP的代码出了什么问题
zerkms 2012年

10

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

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

5

我以您的示例为例进行了编辑:

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
           ELSE NULL
           END)


1

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

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 

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

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 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.