Чи можу я використовувати оператор CASE в умовах JOIN?


141

Наступне зображення є частиною переглядів системи 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заяву. Хтось може допомогти трохи пояснити?


Додати повідомлення про помилку:

Msg 102, рівень 15, стан 1, рядок 6 Неправильний синтаксис біля '='.

це образ


36
Яке програмне забезпечення ви використовували для створення цієї красивої діаграми БД?
LearnByReading

2
@LearnByReading Ви коли-небудь дізналися, яке програмне забезпечення використовується?
Користувач632716,

1
@ User632716, на жаль, ні!
LearnByReading

2
@ User632716 Хоча я дійсно думаю, що це MySQL Workbench. Але я так і не отримав відповіді
LearnByReading

@LearnByReading Я поняття не маю. Це надає Microsoft.
Просто учень

Відповіді:


223

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 спасибі, що працювало на мене ... але проблема полягає в тому, що коли я це роблю, умови роблять провал ... скажіть, будь ласка, як я можу це порушити?
Сагар Тандель

1
@SagarTandel - Вибачте, я не розумію "зробити провал" і "як я його зламаю". Чи можете ви пояснити свій коментар? (Нещодавно спливав із занурення з Саби. Можливо, буде нітрокс.)
HABO

Він перевіряє всі умови, яких я не хочу. Я хочу, щоб він припинив справу, як тільки він відповідає умові.
Сагар Тандель

3
@SagarTandel - Від MSDN : "Оператор CASE оцінює свої умови послідовно і зупиняється на першій умові, умову якої задоволено." Якщо ви хочете, щоб усі об'єднані рядки не відповідали жодному із чітко зазначених умов, просто змініть кінець хвоста = 1на на = 0, але я не думаю, що результат вам сподобається.
HABO

ПРИЄДНАЙТЕСЬ sys.allocation_units НА СЛУЧАЙ, КОЛИ a.type IN (1, 3) AND a.container_id = p.hobt_id ТОЛЬКИ 1 КОЛИ a.type IN (2) AND a.container_id = p.partition_id ТАЛИ 1 ELSE 0 END = 1 ви могли б написати це в рамках Entity вищезазначене рішення
r.hamd

36

Натомість ви просто ПРИЄДНАЄТЬСЯ до обох таблиць, а в пункті SELECT повертайте дані з тієї, що відповідає:

Я пропоную вам перейти за цим посиланням Умовні приєднання до заяви про SQL Server та випадок T-SQL у пункті ПРИЄДНАЙТЕСЬ НА ВІДПРАВЛЕННЯ

напр

    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означає? Кожне з'єднання (крім хреста) є умовним. Чим цей випадок відрізняється від будь-якого іншого? Ваш зразок має внутрішнє з'єднання з умовою, а також запит на ОП поєднується з умовою.
zerkms

@zerkms: Я згоден, це звучить заплутано. Я вважаю, що умовне приєднання в цьому контексті означає приєднання, стан якого залежить від іншої умови.
Андрій М

@Andriy M: Чи є якась причина думати про інший термін для тривіального стану OR?
zerkms

@zerkms: Е, так, це звучить заплутано. :) Але я вважаю, ви хотіли запитати, чи є якась причина не придумати інший термін, і в цьому випадку я не можу бути впевнений. Якщо ви запитуєте мої причини, ну, я думаю, що я просто не міг насторожитися. :) Як щодо об’єднання з альтернативними умовами ? Я боюся, що я не дуже добре вживаюсь. Зауважте, що концептуально йдеться про "умовний стан", а не про "умову з OR". Використання OR- це лише один із способів його реалізації.
Андрій М

@Андрій М: гаразд. Але особисто я все ще не бачу причини називати тривіальний стан з 1 ORі 2 ANDsабо з 1 CASE. Це звичайний запит, який не має нічого, що відрізняє його від будь-якого іншого.
zerkms

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)

Хоча це спрацювало б - запит у питанні виглядає цілком коректним. Тож досі не пояснюється, що не так з кодом ОП
zerkms

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 визначається як "Істинне" чи "Невірне"

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

Це здається приємним

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

Спробуючи це, я отримую помилку: ім'я кореляції 'xx' вказується кілька разів у пункті FROM.
Етьєн

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, коли різні поля повинні бути пов'язані на основі вибору користувачем.

Початковий випадок встановлює вибір поля на основі вибору, і тоді я можу встановити поле, яке мені потрібно відповідати для з'єднання.

Другий випадок випадку може бути доданий для правої частини, якщо потрібна змінна для вибору з різних полів

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 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.