Использование подзапроса в предложении соединения вместо имени столбца - PullRequest
0 голосов
/ 24 апреля 2019

Я пытаюсь присоединиться к двум столам.Один столбец существует в таблице, но другой является производным.

event_date - exists directly in the table
deploy_date - derived using case statement

См. Строку # 6 в исходном запросе.

   1 SELECT    ab.id, 
   2          ab.event_date, 
   3           CASE 
   4                     WHEN ab.label = 'ABC' THEN ab.event_date 
   5                     WHEN ab.label = 'DEF' THEN ab.start_date 
   6           END deploy_date, 
   7 FROM      ab_bro AB 
   8  LEFT JOIN ab_rev rv 
   9 ON        ab.bro_id = rv.bro_id 
   10 AND       ab.event_date = rv.event_date 

Теперь я хочу использовать deploy_date вместоevent_date в строке # 10 (выше) Поскольку sql не позволяет использовать псевдоним в соединениях, я попытался использовать подзапрос

SELECT    ab.id, 
          ab.event_date, 
          CASE 
                    WHEN ab.label = 'ABC' THEN ab.event_date 
                    WHEN ab.label = 'DEF' THEN ab.start_date 
          END deploy_date, 
FROM      ab_bro AB 
LEFT JOIN ab_rev rv 
ON        ab.bro_id = rv.bro_id 
AND 
          ( 
             SELECT 
                 CASE 
                     WHEN AC.label = 'ABC' THEN AC.event_date 
                     WHEN AC.label = 'DEF' THEN AC.start_date 
                  END deploy_date from ab_bro AC) = rv.event_date 

Моя ошибка -

ОШИБКА: более одной строки, возвращенной подзапросом, используемым в качестве выражения

Я понимаю, что мой подзапрос действительно возвращает более одной строки, но я не знаю, как это исправить.

Ответы [ 4 ]

1 голос
/ 24 апреля 2019

Все, что вам нужно сделать здесь, это использовать выражение CASE в ваших критериях JOIN:

SELECT
    ab.id,
    ab.event_date,
    CASE
        WHEN ab.label = 'ABC'
            THEN ab.event_date
        WHEN ab.label = 'DEF'
            THEN ab.start_date
    END deploy_date,
FROM ab_bro AB
    LEFT JOIN ab_rev rv
        ON ab.bro_id = rv.bro_id 
        AND rv.event_date = CASE
                WHEN ab.label = 'ABC'
                    THEN ab.event_date
                WHEN ab.label = 'DEF'
                    THEN ab.start_date
                END
0 голосов
/ 24 апреля 2019
SELECT sub.id,
    sub.event_date,
    sub.deploy_date
FROM (
    SELECT ab.id, 
        ab.event_date, 
        ab.bro_id,
        CASE 
            WHEN ab.label = 'ABC' THEN ab.event_date 
            WHEN ab.label = 'DEF' THEN ab.start_date END as deploy_date, 
    FROM ab_bro AB 
    ) AS sub
LEFT JOIN ab_rev rv ON sub.bro_id = rv.bro_id 
AND sub.deploy_date = rv.event_date; 
0 голосов
/ 24 апреля 2019

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

WITH x AS (
  SELECT
    id,
    bro_id,
    event_date,
    CASE label
      WHEN 'ABC' THEN event_date 
      WHEN 'DEF' THEN start_date 
    END deploy_date
  FROM ab_bro
)
SELECT
  x.id, 
  x.event_date, 
  x.deploy_date
FROM
  x
  LEFT JOIN ab_rev rv 
    ON x.bro_id = rv.bro_id 
      AND x.deploy_date = rv.event_date

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

0 голосов
/ 24 апреля 2019

Если AND () выбирает retunr больше чем строк, вы можете использовать limit1

SELECT    ab.id, 
          ab.event_date, 
          CASE 
                    WHEN ab.label = 'ABC' THEN ab.event_date 
                    WHEN ab.label = 'DEF' THEN ab.start_date 
          END deploy_date, 
FROM      ab_bro AB 
LEFT JOIN ab_rev rv 
ON        ab.bro_id = rv.bro_id 
AND   ( 
             SELECT 
                 CASE 
                     WHEN AC.label = 'ABC' THEN AC.event_date 
                     WHEN AC.label = 'DEF' THEN AC.start_date   
                  END deploy_date from ab_bro AC
                  limit 1 ) = rv.event_date 

или использовать IN вместо =

  SELECT    ab.id, 
          ab.event_date, 
          CASE 
                    WHEN ab.label = 'ABC' THEN ab.event_date 
                    WHEN ab.label = 'DEF' THEN ab.start_date 
          END deploy_date, 
FROM      ab_bro AB 
LEFT JOIN ab_rev rv 
ON        ab.bro_id = rv.bro_id 
AND  rv.event_date IN  ( 
             SELECT 
                 CASE 
                     WHEN AC.label = 'ABC' THEN AC.event_date 
                     WHEN AC.label = 'DEF' THEN AC.start_date   
                  END deploy_date from ab_bro AC
                  limit 1 )
...