如何在被父查询列过滤后有效地 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
我从一个非常大且复杂的查询开始,该查询本质上是 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 扫描运行.
这看起来应该很简单,但在这一点上,我认为我患有非常严重的隧道视野,无法看到我已经拥有的东西。如果能在正确的方向上给予一些温和的提示,我将不胜感激!
编辑:我应该提一下,我不仅需要来自子查询的权重标量值,我还需要该权重的记录时间。
在您的 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