如何在被父查询列过滤后有效地 return 来自子查询的最小值

How to efficiently return minimum value from subquery after being filtered by parent query column

我从一个非常大且复杂的查询开始,该查询本质上是 returns 一堆关于手术日志的数据,但最终每一行代表一个日志并具有一个唯一的日志 ID。对于这个查询,我试图在手术前添加患者最近的体重测量值。不幸的是,我很难有效地加入这些数据。

这里是查询的简化表示:

SELECT or_log.log_id, or_log.start_dt, weight.*
FROM or_log
LEFT OUTER JOIN
    (
        SELECT measurement.log_id, measurement.recorded_time, ROUND(measurement.meas_value,2) AS "WEIGHT",
            ROW_NUMBER() OVER (PARTITION BY measurement.log_id ORDER BY measurement.recorded_time DESC) AS r
        FROM measurement
        WHERE measurement.type='weight'
    ) weight ON weight.log_id=or_log.log_id AND weight.r=1

这实际上工作正常,但不会将体重测量值限制为手术前的体重测量值,它只提供最近的体重测量值。我需要向子查询添加一个 where 子句,表示 weight.recorded_time <= or_log.start_dt。问题是无法从子查询中引用 or_log.start_dt。如果我尝试从子查询中引用 or_log table(这使我能够到达 or_log.start_dt),它会对 table 进行完整的 table 扫描运行.

需要 1200 万年

这看起来应该很简单,但在这一点上,我认为我患有非常严重的隧道视野,无法看到我已经拥有的东西。如果能在正确的方向上给予一些温和的提示,我将不胜感激!

编辑:我应该提一下,我不仅需要来自子查询的权重标量值,我还需要该权重的记录时间。

在您的 select 中使用子查询:

SELECT or_log.log_id, or_log.start_dt, 
(select row_to_json(x.*) from (
 SELECT measurement.log_id, measurement.recorded_time,         ROUND(measurement.meas_value,2) AS "WEIGHT",
            ROW_NUMBER() OVER (PARTITION BY measurement.log_id ORDER BY     measurement.recorded_time DESC) AS r
        FROM measurement
        WHERE measurement.type='weight'
and measurement.log_id=or_log.log_id
) x where x.r=1)
FROM or_log

显然,您需要进行额外的过滤,但您可以在内部查询中引用 or_log。

这可能看起来太简单了,但为什么不直接连接表,然后过滤 row_number() 结果。

SELECT
      *
FROM (
      SELECT
            or_log.log_id
          , or_log.start_dt
          , w.recorded_time
          , ROUND(w.meas_value, 2) AS "WEIGHT"
          , NVL(ROW_NUMBER() OVER (PARTITION BY w.log_id ORDER BY w.recorded_time DESC), 1) AS r
      FROM or_log
            LEFT OUTER JOIN measurement w ON or_log.log_id = w.log_id
                        AND w.type = 'weight'
                        AND w.recorded_time <= or_log.start_dt
      ) d
WHERE d.r = 1

备选方案:不使用 NVL(),然后过滤

d.r = 1 or d.r is null