当前位置: 首页 > 面试题库 >

窗口函数通过当前行过滤

章昊
2023-03-14
问题内容

这是该问题的后续内容,其中对我的查询进行了改进,使其使用窗口函数而不是联接内的聚合LATERAL。虽然查询现在快得多,但我发现结果不正确。

我需要在x年尾随时间框架上执行计算。例如,price_to_maximum_earnings每行的计算方法是:max(earnings)十年前移至当前行,然后除以price结果。为了简单起见,我们将使用1年。

SQL Fiddle对此问题进行了解答。(Postgres 9.6)

作为一个简单的例子,pricepeak_earnings用于2010-01-01可像这样分别计算:

SELECT price
FROM security_data
WHERE date = '2010-01-01'
AND security_id = 'SPX';

SELECT max(earnings) AS min_earnings
FROM bloomberg.security_data
WHERE date >= '2000-01-01'
AND date <= '2010-01-01'
AND security_id = 'SPX';

要做到这一点 ,每行 ,我用的是以下情况:

SELECT security_id, date, price
     , CASE WHEN date1 >= min_date
            THEN price / NULLIF(max(earnings) FILTER (WHERE date >= date1) OVER w, 0) END AS price_to_peak_earnings
FROM
(
  SELECT record_id, security_id, price, date, earnings
           , (date - interval '1 y')::date AS date1
           , min(date) OVER (PARTITION BY security_id) AS min_date
      FROM   security_data
) d
WINDOW w AS (PARTITION BY security_id);

我认为这里的问题源于的使用FILTER,因为它似乎并没有按我希望的那样工作。请注意,在链接的SQL
Fiddle中,我显示了的结果FILTER,对于每一行,peak_earningsandminimum_earnings均为整个数据集的最大值和最小值。它们
应该earnings1年前到当前行的最大值/最小值。

这里发生了什么?从这个问题的答案中我知道我不能简单地说FILTER (WHERE date >= date1 AND date <=current_row.date),那么我是否缺少解决方案?我无法使用窗口框架,因为在任何给定的时间范围内,行数都是不确定的,所以我不能只说OVER (ROWS BETWEEN 365 PRECEDING AND CURRENT ROW)。我可以使用框架
滤镜吗?那可能会超过一年,然后筛选器可以捕获每个无效的日期。我已经尝试过了,但是没有成功。


问题答案:

我可以使用框架和滤镜吗?

可以的 。但是两者都有限制:

  • FILTER子句中的表达式只能看到其获取值的相应行。无法引用窗口函数为其计算值的行。因此 除非我们进行 巨大而昂贵的 交叉 联接, 否则我看不到根据 行制定过滤器的方法-同一行用于许多不同的计算。或者,我们又回到了LATERAL那个子查询 引用父行。

这些限制使您的特定查询难以实施。现在应该是 正确的

SELECT *
FROM  (
   SELECT record_id, security_id, date, price
        , CASE WHEN do_calc THEN                max(earnings) OVER w1     END AS peak_earnings
        , CASE WHEN do_calc THEN                min(earnings) OVER w1     END AS minimum_earnings
        , CASE WHEN do_calc THEN price / NULLIF(max(earnings) OVER w1, 0) END AS price_to_peak_earnings
        , CASE WHEN do_calc THEN price / NULLIF(min(earnings) OVER w1, 0) END AS price_to_minimum_earnings
   FROM  (
      SELECT *, (date - 365) >= min_date AND s.record_id IS NOT NULL AS do_calc
      FROM  (
         SELECT security_id, min_date
              , generate_series(min_date, max_date, interval '1 day')::date AS date
         FROM  (
            SELECT security_id, min(date) AS min_date, max(date) AS max_date
            FROM   security_data
            GROUP  BY 1
            ) minmax
         ) d
      LEFT   JOIN  security_data s USING (security_id, date)
      ) sub1
   WINDOW w1 AS (PARTITION BY security_id ORDER BY date ROWS BETWEEN 365 PRECEDING AND 1 PRECEDING)
   ) sub2
WHERE  record_id IS NOT NULL 
ORDER  BY 1, 2;

SQL提琴。

笔记

  • 问题中没有什么可以说每个security_id人在同一天都有行。计算security_id子查询中每个的最小/最大日期minmax将为我们提供最短的时间范围。

  • 计算的时间范围恰好是该行当前日期之前的365天,并且 包括当前行(ROWS BETWEEN 365 PRECEDING AND 1 PRECEDING)。通常, 当前行从要与当前行进行比较的聚合中 排除 会更有用。
    我将计算条件调整到了相同的时间范围,以避免出现极端情况:(date - 365) >= min_date

  • 在小提琴中,在1月1日的每一行中添加了1行,您可以看到leap年与固定天数365天形成对比的效果。leap年(2001,2005,…)之后,窗框为空。

  • 我正在使用所有子查询,通常比CTE快一点。

  • 可以肯定的是,我们需要ORDER BY在框架定义中包括。

  • 我将“ 1年”期间w1用作窗口 名称 。您可以添加w2,等等,每个可以有任意天数。毕竟,如果需要,您可以适应leap年。甚至可能根据当前日期生成整个查询…


 类似资料:
  • 问题内容: 好的,起初这只是和我的一个朋友开玩笑,但后来变成了有趣的技术问题:) 我有下表: 该表包含我所有东西的记录,并分别具有数量和优先级(我需要多少)。 我有一个指定体积的袋子,例如。我想从表中选择所有可以放入袋子的东西,首先包装最重要的东西。 这似乎是使用窗口函数的情况,所以这是我想出的查询: 但是,问题在于Postgres抱怨: 如果我删除此过滤器,则会正确计算总列,对结果进行正确排序,

  • 我有以下数据: 现在我想以这样一种方式过滤数据,我可以删除第6行和第7行,对于特定的uid,我想在代码中只保留一行值为'c' 所以预期的数据应该是: 我使用的窗口函数如下所示:

  • 问题内容: 我正在试验Firefox的WebDriver,请问是否可以处理“下载”窗口(接受或拒绝传入的下载请求)? 例如,一段简单的代码: 我已经对此进行了一些尝试,但是还没有找到解决方案。我真的很感谢任何提示。 非常感谢,-V 问题答案: 一种解决方案是更改WebDriver的Firefox配置文件,以将某些MIME类型自动下载到给定目录。 我不确定如何(或是否)在Python中公开此信息,但

  • 问题内容: 我需要通过控制器中的代码关闭当前的fxml窗口 我知道stage.close()或stage.hide()在fx中做到这一点 如何在fxml中实现呢?我试过了 但这不起作用! 所有帮助将不胜感激。谢谢! 问题答案: 如果您还没有关闭按钮,请给它一个fx:id: 在您的控制器类中:

  • 问题内容: 在上一个问题中,我需要计算一个变量出现的次数。 提供的代码如下: 但是,现在我需要对该代码进行改进: 假设我有下表: 现在,我需要计算特定时间段内的出现次数。期望的输出如下(为简单起见,假设时间范围为n = 2天) 也就是说,我需要知道在过去的“ n”个月中,代码“ x”在我的表中出现了多少次。 它在SQL Server 2012中运行。 先感谢您。 问题答案: 将选项与CTE,CRO

  • 问题内容: 如您所知,可以如下初始化对象: 是否可以通过函数定义类似这样的对象: 我的目标实际上是从API中获取对象,并通过ng-repeat将它们显示在列表中 问题答案: 该文件说将采用任何表达方式。因此,是的,只要关联的作用域定义了一个称为的函数,您就可以做上面的事情(我也为乐趣进行了验证)。 请注意,该文档说,这实际上仅旨在用于别名: ngInit用于别名化ngRepeat的特殊属性的唯一适