Можно ли использовать оператор CASE в условии JOIN?

Следующее изображение является частью Microsoft SQL Server 2008 R2 System Views. Из изображения видно, что связь между 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. Может ли кто-нибудь помочь немного объяснить?


Добавьте сообщение об ошибке:

Msg 102, Level 15, State 1, Line 6 Incorrect syntax near '='.

Комментарии к вопросу (7)
Решение

Выражение 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 был типом данных, тогда проверка на равенство имела бы смысл).

Комментарии (6)

Вместо этого вы просто соединяете обе таблицы, а в предложении SELECT, возвращаете данные из той таблицы, которая совпадает:

Я предлагаю вам пройти по этой ссылке Conditional Joins in SQL Server и https://stackoverflow.com/questions/8361183/t-sql-case-statement-in-a-join-on-clause.

например.

    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 

Edit: As per comments.

Вы не можете указать условие присоединения, как вы это делаете... Проверьте запрос выше, который не имеет ошибки. Я убрал общий столбец вверх и значение правого столбца будет оцениваться по условию.

Комментарии (9)

Попробуйте это:

...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)
Комментарии (1)

Я думаю, что вам нужно два случае заявления:

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 возвращает одно значение в конце <БР>
  • в заявлении сравнивает два значения <БР>
  • ваше заявление дело делать inside сравнения оператор Case. Я думаю, что если вы поставите вашем случае заявление в ваш выбор вы получили бы логическое '1' или '0', указывающее, является ли случай заявления true или false <БР>
Комментарии (0)

Это выглядит красиво

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)

Взял DonkeyKong'ы например.

Проблема мне нужно использовать объявленную переменную. Это позволяет утверждать левой и правой стороны, что нужно сравнивать. Это для поддержки SSRS отчет, где разные поля должны быть связаны в зависимости от выбора пользователя.

В первоначальном случае устанавливает поле выбора на основе выбора и тогда я смогу установить поле мне нужно, чтобы матч на присоединиться.

Второе заявление, дело может быть добавлен к правой стороне при переменная нужна, чтобы выбирать из разных областей

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 
Комментарии (0)