【问题标题】:Left Join with Multiple Conditions and MAX Value具有多个条件和最大值的左连接
【发布时间】:2019-01-17 00:35:39
【问题描述】:

我正在尝试执行左连接,其中必须满足多个条件,包括拉入满足这些条件的 MAX 序列号。

左连接位于两个表中的唯一标识符上。表 acaps_history 对于每个 app_id 都有几行。我只需要拉入具有最高 seq_number 和 'XU' 的 activity_code 的一行。如果给定的 app_id 不存在代码“XU”,那么上面的 case 语句应该为该行返回“N”。我目前的代码不起作用 - 返回错误“列可能未外连接到子查询”:

create table orig_play3 as   
   (select 
    x.*, 
    case when xa.activity_code in 'XU' then 'Y' else 'N' end as cpo_flag

    from 
    dfs_tab_orig_play_x x

    left join cf.acaps_history xa on 
    x.APP_ID = xa.FOC_APPL_ID
    and xa.activity_code in 'XU'
    and xa.seq_number = (select max(seq_number) from cf.acaps_history where FOC_APPL_ID=x.app_id)
    )

【问题讨论】:

  • 是否只需要检查xa是否包含每个x.APP_ID的特定活动代码的记录(或检查最后一条记录是否有此活动代码)?如果是这样,我建议使用子查询而不是左连接。
  • 我需要检查xa 是否包含每个x.app_id 的代码“XU”。如果是,则仅拉入具有最大序列号的记录。当xa 中的 app_id 多次列出代码“XU”时,最大序列号是相关的。
  • 试试select x.*, (select decode(count(*), 0, 'N', 'Y') from cf.acaps_history xa where x.app_id = xa.foc_appl_id and xa.activity_code = 'XU') from dfs_tab_orig_play_x x。我看不到你在哪里使用了 xa 中的其他一些数据,所以不需要外连接它...

标签: oracle subquery max left-join outer-join


【解决方案1】:

如果您在 12c 上,我喜欢 OUTER APPLY 这样的事情,因为它可以让您按 seq_number 降序对每个 app_id 的行进行排序,然后只选择最高的行。

SELECT
    x.*,
    CASE
            WHEN xa.activity_code IN 'XU' THEN 'Y'
            ELSE 'N'
        END
    AS cpo_flag
FROM
    dfs_tab_orig_play_x x
    OUTER APPLY ( SELECT *
                  FROM   cf.acaps_history xa
                  WHERE  xa.foc_appl_id = x.app_id
                  AND    xa.activity_code = 'XU'
                  ORDER BY xa.seq_number DESC
                  FETCH FIRST 1 ROW ONLY ) xa

注意:此逻辑与您发布的内容略有不同。在此版本中,它将加入给定app_id 的“XU”记录中具有最高seq_numberacaps_history 行。对于给定的app_id,您的版本正在加入具有最高seq_number 的行,无论该行是否为“XU”行。我假设(几乎没有理由)这是您的错误。但是,如果不是,我的版本将无法正常工作。

【讨论】:

    【解决方案2】:

    这可能是执行此查询的最低效的方式,但它有效...运行大约需要 3 分钟(表大小超过 600K 行),但它再次返回了我需要的结果:

    create table test as (
      select x.*,
      case when xb.activity_code in 'XU' then 'Y' else 'N' end as cpo_flag
    
      from dfs_tab_orig_play_x x
    
       left join
           (select 
           xa.FOC_APPL_ID, xa.activity_code, xa.seq_number
           from dfs_tab_orig_play_x x, cf.acaps_history xa
           where x.app_id = xa.FOC_APPL_ID (+)
           and xa.seq_number = (select max(seq_number) from cf.acaps_history where 
           x.app_id=FOC_APPL_ID(+) and activity_code in 'XU')) xb
       on x.app_id = xb.FOC_APPL_ID (+)
     )
    

    【讨论】:

      【解决方案3】:

      鉴于您的错误,问题似乎是您查询的最后一部分:

      and xa.seq_number = (select max(seq_number) from cf.acaps_history where FOC_APPL_ID=x.app_id)
      

      这仍然是在 ON 子句的上下文中运行,所以查找最大序列号的子查询是问题。

      您应该能够通过将该子查询移出 ON 子句来避免这种情况:

      LEFT JOIN (
                SELECT FOC_APPL_ID, activity_code, seq_number
                FROM cf.acaps_history
                WHERE activity_code in 'XU'
      ) xa
      ON x.APP_ID = xa.FOC_APPL_ID
      WHERE xa.seq_number = (select max(ah.seq_number) from cf.acaps_history ah where ah.FOC_APPL_ID=x.app_id and ah.activity_code in 'XU')
      

      【讨论】:

      • 运行该代码我收到错误:“X”。“APP_ID”:标识符无效。是否需要在子查询中重新定义驱动表(dfs_tab_orig_play_xx)?
      • @A.Oli 啊,这很有道理。我相信您应该能够在外部查询的 where 子句中进行相同的检查,因为连接已经在该上下文中执行。我已经更新了我的答案,试试这个,如果你有更好的运气,请告诉我。
      • @A.Oli 啊,我认为返回的序列号可能是针对没有将activity_code 设置为“XU”的记录。我已经添加了这一点,并试图更好地限定某些列,以防发生某种冲突。如果您仍然对这些更改有疑问,但我建议您剥离 WHERE 子句或查询的其他部分,以查看返回了哪些数据以及是否有某些内容意外被错误地过滤掉。既然您没有收到错误,那么调试它应该会容易一些。
      猜你喜欢
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 2012-01-08
      • 1970-01-01
      • 2021-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多