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

Следующее изображение является частью системных представлений 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 Неверный синтаксис рядом с '='.

this is the image

Ответ 1

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

Ответ 2

Вместо этого вы просто ПРИСОЕДИНЯЕТЕСЬ к обеим таблицам, и в своем предложении SELECT возвращаете данные из той, которая соответствует:

Я предлагаю вам пройти по этой ссылке Условные объединения в SQL Server и Оператор T-SQL в предложении JOIN ON

например

    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 

Изменение: в соответствии с комментариями.

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

Ответ 3

Попробуйте следующее:

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

Ответ 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 возвращает одно значение в конце
  • оператор ON сравнивает два значения
  • ваш оператор CASE делал сравнение внутри оператора CASE. Я полагаю, что если вы поместите свой оператор CASE в свой SELECT, вы получите логическое значение "1" или "0", указывающее, был ли оператор CASE оценен как True или False

Ответ 6

Я взял твой пример и отредактировал его:

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

Здесь я сравнил разницу в двух разных наборах результатов. Надеюсь, это может быть полезно.

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

Взял пример 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