在子查询中使用 row_number() 导致 ORA-00913: 值太多

Using row_number() in subquery results in ORA-00913: too many values

在 Oracle 中,我希望执行类似下面的 SQL 的操作。对于 "criteria," 中的每一行,我想在另一个 table(按 last_modified_date)中找到相同 location_id 的最新行,并使用该值设置 default_start_interval.或者,如果没有这样的值,则使用 30。但是,如您所见,子查询必须在 select 语句中有两个值才能使用 row_number()。这会导致错误。我如何重新格式化它才能正常工作?

update criteria pc set default_start_interval = 
    COALESCE(
        (SELECT start_interval, 
                row_number() over(partition by aday.location_id 
                                  order by atime.last_modified_date desc
                             ) as rn
            FROM available_time atime 
            JOIN available_day aday ON aday.available_day_id = atime.available_day_id
            WHERE aday.location_id = pc.location_id
                and rn = 1)
        , 30)

您的更新查询中有两个问题:

  1. 更新预计 default_start_interval 每行只有一个值,但是 select 列表中有两列。

  2. 行号应该在内层查询之前分配,然后在外层查询应用过滤器where rn = 1

您的更新查询应如下所示:

UPDATE criteria pc
SET default_start_interval = NVL(
    (
    SELECT start_interval FROM(
        SELECT
            start_interval, ROW_NUMBER() OVER(
                PARTITION BY aday.location_id 
                ORDER BY atime.last_modified_date DESC
            ) AS rn
        FROM
            available_time atime
            JOIN available_day aday ON aday.available_day_id = atime.available_day_id
        WHERE
            aday.location_id = pc.location_id
        )
    WHERE rn = 1)
    , 30)

注意: 您可以简单地使用 NVL 而不是 COALESCE,因为您只有一个值来检查 NULL。当您有多个表达式时,COALESCE 很有用。

我认为更简单的方法是使用聚合和 keep 来获取您想要的值:

update criteria pc
    set default_start_interval = 
            (select coalesce(max(start_interval) keep (dense_rank first order by atime.last_modified_date desc), 30)
             from available_time atime join
                  available_day aday 
                  on aday.available_day_id = atime.available_day_id
             where aday.location_id = pc.location_id
            );

没有 GROUP 的聚合查询总是 returns 一行。如果没有行匹配,则返回值为 NULL——COALESCE() 捕获这种情况。