Какие есть варианты для вложенной структуры типа case в объединении таблиц в TSQL?

#sql-server #tsql #join #nested

#sql-server #tsql #Присоединиться #вложенный

Вопрос:

Мне нужно объединить два условия — первое простое, но второе, похоже, запрашивает вложенный оператор case, но я не смог понять, как заставить его работать или лучший вариант.

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

Это отлично работает:

 Inner join table x on x.ser = y.ser and (case when X <= 12 then 9 else 
15) = (case when Y <= 12 then 9 else 15)
  

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

 case when (code = BID) then 
(case when X <= 12 then 9 else 15) = (case when Y <= 12 then 9 else 15)
else X = Y
  

Фактический нерабочий код приведен ниже.

     INNER JOIN dbo.Image img on img.Ser = sa.Ser and 
        case when (ac.ActivityCode = 'BID') then    
            CASE WHEN DATEPART(hour, img.CreationDate) <= 12 THEN 
                 DATEADD(hh, 9, DATEADD(dd, DATEDIFF(dd, 0, 
                 img.CreationDate), 0)) ELSE DATEADD(hh, 15, DATEADD(dd, 
                 DATEDIFF(dd, 0, img.CreationDate), 0))  
            END = CASE WHEN DATEPART(hour, sa.ActualStartDate) <= 12 THEN 
                       DATEADD(hh, 9, DATEADD(dd, DATEDIFF(dd, 0, 
                        sa.ActualStartDate), 0)) ELSE DATEADD(hh, 15, 
                        DATEADD(dd, DATEDIFF(dd, 0, sa.ActualStartDate), 
                        0)) 
                    END 
          ELSE  sa.ActualStartDate = img.CreationDate
        END
  

Комментарии:

1. вы пытались разделить запрос на 2 запроса (один для одного действия, а другой для нескольких действий)? если нет, попробуйте сначала разделить их, получить правильные результаты для обоих запросов, затем просмотрите их оба и измените их настолько, насколько сможете, затем посмотрите, что вы можете сделать, чтобы объединить их оба в одном запросе.

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

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

Ответ №1:

Вы не можете иметь оператор сравнения {expression 1} = {expression 2} внутри CASE оператора.

Это должно быть что-то вроде

 INNER JOIN dbo.Image img  on  img.Ser = sa.Ser 
                         and  CASE ... END = CASE ... END
  

Но тогда ваш запрос будет трудно прочитать. Почему бы не использовать a CTE . И вычислите новое выражение внутри CTE

 ; WITH
CTE1 AS 
( 
    Col2 = CASE WHEN DATEPART(hour, img.CreationDate) <= 12 .....
),
CTE2 AS 
( 
    Col2 = CASE WHEN DATEPART(hour, sa.ActualStartDate) <= 12 .....
)
SELECT *
FROM   CTE1 c1 
JOIN   CTE2 c2  ON c1.Ser  = c2.Ser
               AND c2.Col2 = c2.Col2