在连接子句中使用子查询而不是列名

Using subquery in join clause instead of column name

我正在尝试加入两个table。 table 中存在一列,但另一列是派生的。

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 

现在我想在第 10 行(上面)中使用 deploy_date 而不是 event_date 由于 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 

我的错误-

ERROR: more than one row returned by a subquery used as an expression

我知道我的子查询确实返回了不止一行,但我不知道如何解决这个问题。

您在这里需要做的就是在 JOIN 条件中使用该 CASE 表达式:

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

如果 AND ( ) 子选择返回的行数多于您可以使用限制 1

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 )

加入内联视图而不是在 WHERE 子句中放置 CASE 语句至少会更整洁一些。这将使您避免重复 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

您可以将这两种变体视为创建一个临时 table 包含作为普通列的派生数据,并将其连接到另一个 table。

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;