窗口函数或公共表表达式:计算范围内的前几行

2024-04-12

我想使用窗口函数来确定每一行满足特定条件的先前记录的总数。

一个具体的例子:

clone=# \d test
              Table "pg_temp_2.test"
 Column |            Type             | Modifiers 
--------+-----------------------------+-----------
 id     | bigint                      | 
 date   | timestamp without time zone | 

我想知道每个date'之前 1 小时内'的行数date.

我可以用窗口函数来做到这一点吗?或者我需要调查 CTE 吗?

我真的希望能够写出类似的东西(不起作用):

SELECT id, date, count(*) OVER (HAVING previous_rows.date >= (date - '1 hour'::interval))
FROM test;

我可以通过加入针对自身的测试来编写此内容,如下所示 - 但这不会随着特别大的表而扩展。

SELECT a.id, a.date, count(b.*)-1 
FROM test a, test b 
WHERE (b.date >= a.date - '1 hour'::interval AND b.date < a.date)
GROUP BY 1,2
ORDER BY 2;

我可以用递归查询来做这件事吗?还是常规 CTE? 我对 CTE 还不是很了解。我有预感我很快就会去。 :)


我认为你不能用简单的查询、CTE 和窗口函数便宜地做到这一点 - 它们的框架定义是静态的,但你需要一个动态框架(取决于列值)。

一般来说,您必须仔细定义窗口的下限和上限:以下查询exclude当前行和include下边框。
仍然有一个细微的差别:该函数包括当前行的前一个同级,而相关子查询则排除它们......

测试用例

Using ts而不是保留字date作为列名。

CREATE TABLE test (
  id  bigint
, ts  timestamp
);

ROM - 罗曼的查询 https://stackoverflow.com/a/18175342/939860

使用 CTE,将时间戳聚合到数组中,取消嵌套,计数...
虽然正确,但性能急剧恶化有一手多的行。这里有几个性能杀手。见下文。

ARR - 计数数组元素

我接受了 Roman 的查询并尝试简化它:

  • 删除不必要的第二个 CTE。
  • 将第一个 CTE 转换为子查询,速度更快。
  • Direct count()而不是重新聚合到数组中并用array_length().

但数组处理成本高昂,而且性能仍然不佳严重恶化有更多行。

SELECT id, ts
     , (SELECT count(*)::int - 1
        FROM   unnest(dates) x
        WHERE  x >= sub.ts - interval '1h') AS ct
FROM (
   SELECT id, ts
        , array_agg(ts) OVER(ORDER BY ts) AS dates
   FROM   test
   ) sub;

COR-- 相关子查询

You could用一个简单的相关子查询来解决它。速度快了很多,但仍然...

SELECT id, ts
     , (SELECT count(*)
        FROM   test t1
        WHERE  t1.ts >= t.ts - interval '1h'
        AND    t1.ts < t.ts) AS ct
FROM   test t
ORDER  BY ts;

FNC-功能

按时间顺序循环行row_number() in plpgsql 函数并将其与cursor https://www.postgresql.org/docs/current/plpgsql-cursors.html在同一查询上,跨越所需的时间范围。然后我们可以减去行数:

CREATE OR REPLACE FUNCTION running_window_ct(_intv interval = '1 hour')
  RETURNS TABLE (id bigint, ts timestamp, ct int)
  LANGUAGE plpgsql AS
$func$
DECLARE
   cur   CURSOR FOR
         SELECT t.ts + _intv AS ts1, row_number() OVER (ORDER BY t.ts) AS rn
         FROM   test t ORDER BY t.ts;
   rec   record;
   rn    int;

BEGIN
   OPEN cur;
   FETCH cur INTO rec;
   ct := -1;  -- init

   FOR id, ts, rn IN
      SELECT t.id, t.ts, row_number() OVER (ORDER BY t.ts)
      FROM   test t ORDER BY t.ts
   LOOP
      IF rec.ts1 >= ts THEN
         ct := ct + 1;
      ELSE
         LOOP
            FETCH cur INTO rec;
            EXIT WHEN rec.ts1 >= ts;
         END LOOP;
         ct := rn - rec.rn;
      END IF;

      RETURN NEXT;
   END LOOP;
END
$func$;

默认一小时间隔的呼叫:

SELECT * FROM running_window_ct();

或任意间隔:

SELECT * FROM running_window_ct('2 hour - 3 second');

db<>fiddle
Old sqlfiddle http://www.sqlfiddle.com/#!17/5faffd/1

基准

根据上面的表格,我在我的旧测试服务器上运行了一个快速基准测试:(Debian 上的 PostgreSQL 9.1.9)。

-- TRUNCATE test;
INSERT INTO test
SELECT g, '2013-08-08'::timestamp
         + g * interval '5 min'
         + random() * 300 * interval '1 min' -- halfway realistic values
FROM   generate_series(1, 10000) g;

CREATE INDEX test_ts_idx ON test (ts);
ANALYZE test;  -- temp table needs manual analyze

我改变了bold每轮比赛的一部分,并取得 5 场最佳成绩EXPLAIN ANALYZE.

100 rows
ROM:27.656 毫秒
ARR:7.834 毫秒
响应时间:5.488 毫秒
FNC: 1.115 ms

1000 行
ROM:2116.029 毫秒
ARR:189.679 毫秒
响应时间:65.802 毫秒
FNC: 8.466 ms

5000行
ROM:51347 毫秒!
ARR:3167 毫秒
响应时间:333 毫秒
FNC: 42 ms

100000 行
游戏ROM:地下城与勇士
到达时间:DNF
响应时间:6760 毫秒
FNC: 828 ms

函数是明显的胜利者。它速度最快一个数量级,并且扩展性最好。
数组处理无法竞争。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

窗口函数或公共表表达式:计算范围内的前几行 的相关文章

  • 如何将可视选择的文本通过管道传输到 UNIX 命令并将输出附加到 Vim 中的当前缓冲区

    使用 Vim 我尝试将在可视模式下选择的文本通过管道传输到 UNIX 命令 并将输出附加到当前文件的末尾 例如 假设我们有一个 SQL 命令 例如 SELECT FROM mytable 我想做如下的事情
  • 为什么这会返回资源 id #2? [复制]

    这个问题在这里已经有答案了 可能的重复 我如何从 PHP 中的 MySql 响应中 回显 资源 id 6 https stackoverflow com questions 4290108 how do i echo a resource
  • Google Cloud SQL - Postgresql 存储不断增长

    我最近开始修补 Google Cloud SQL PostgreSQL 我创建了一个空数据库 在 4 5 天的时间里 其存储使用量已增长到超过 20GB 它一直在上升 但数据库中没有数据 它甚至没有被使用 有谁知道会发生什么以及如何阻止它
  • 如何使用 typeorm 在 postgres 中保存 json 对象数组

    我正在尝试在 postgres 中保存 jsonb 类型的对象数组 Entity Column type jsonb array true nullable true testJson object 我在邮递员中发送的json testJs
  • 使用 JSON 参数的 Postgres 批量 INSERT 函数

    这是一个plpgsqlpostgres 的函数9 6 它试图INSERT一行 如果插入没有失败 由于违反键约束 那么它会运行更多命令 CREATE FUNCTION foo int text text RETURNS void AS BEG
  • postgreSql 中特定时间后表更新

    我已经在 postgres 中创建了表 现在我想在特定时间 例如 1 小时 后更新一行 我看到很多问题 例如 https dba stackexchange com questions 56424 column auto updated a
  • 独立对列进行排序,使得所有空值都位于每列的最后

    这是一个名为的示例表animal name color fox brown fox red dog gold 现在 我想要的是这样的结果 fox dog brown gold red 名称应该是结果的列 不同颜色值作为行 我的第一个想法是
  • 列中差异的数量

    我想检索一列每行中有多少个字母的差异 例如 如果您有一个值 test 而另一行有一个值 testing 则 test 和 testing 之间的差异为 4 个字母 该列的数据值为 4 I have reflected about it an
  • Laravel leftJoin 仅右表的最后一条记录

    我是 Laravel 的新手 我有两张桌子 1 产品 2 价格 products id product int p key name varchar prices id price int p key id product int
  • 跨多个表进行搜索,并在结果行中显示表名称

    如何构建 SQL 语句以跨多个平面不相关的表运行 并使用选择结果和结果来自的表的名称显示结果 这种情况是这样的 我有几个表 每个表都有相同的列名 这是我从外部各方收到的数据 并将其存储在不同的表中 相同的表看起来像 Table 1 pid
  • 单独的逗号分隔值并存储在sql server的表中

    我有一个存储过程 它将逗号分隔的值作为输入 我需要将其分开并需要将其作为单独的行存储在表中 令 SP 的输入为 Rule ID ListType ID Values 1 2 319 400 521 8465 2013 我需要将它存储在一个名
  • MySQL 查询到 CSV [重复]

    这个问题在这里已经有答案了 有没有一种简单的方法来运行MySQL查询来自linux命令行并以csv格式输出结果 这就是我现在正在做的事情 mysql u uid ppwd D dbname lt lt EOQ sed e s g tee l
  • 无法“安装”plpython3u - postgresql

    我正在尝试在 postgresql 中使用 python 语言 像这样的事情 create or replace function test a integer returns integer as if a 2 0 return even
  • 为表中的每个组选择前 N 行

    我面临一个非常常见的问题 即 为表中的每个组选择前 N 行 考虑一个表id name hair colour score列 我想要一个结果集 对于每种头发颜色 都能得到前 3 名得分手的名字 为了解决这个问题 我得到了我所需要的Rick O
  • 检查 postgres 复制状态

    有人可以建议检查 postgresql 复制状态的步骤以及如何确定复制是否未正确进行吗 我们在 pgsql9 0 和 pgsql9 4 中使用流复制 我通常使用以下 SQL 查询来检查 Postgres v11 的状态 关于主人 selec
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 执行带有 EXCEPTION 的 PostgreSQL 查询会导致两条不同的错误消息

    我有一个 PostgreSQL 查询 其中包含事务和列重复时的异常 BEGIN ALTER TABLE public cars ADD COLUMN top speed text EXCEPTION WHEN duplicate colum
  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • Postgres 中的输出 Inserted.id 等效项

    我是 PostgreSQL 新手 正在尝试将 mssql 脚本转换为 Postgres 对于合并语句 我们可以使用冲突更新插入或不执行任何操作 但我使用下面的语句 不确定这是否是正确的方法 MSSQL代码 Declare tab2 New
  • 索引数量越少意味着插入、更新和删除速度更快? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐

  • Hibernate 中的小写注释

    hibernate中有没有办法将实体的列注释为字符串小写 我的意思是例如 Entity public class User Column private String username 我希望休眠在所有未绑定到特定数据库的查询中将用户名转换
  • 如何在 gdb 中附加进程

    我有一个简单的 C 程序 它分叉一个进程 然后运行一个可执行文件 我想将子进程附加到 gdb 我在控制台中运行主程序并打开另一个控制台来查找子进程的 pid 然后使用以下命令启动 gdb gdb attach 12271 where 122
  • 不需要的空白导致列扭曲

    我正在尝试从间隔 非制表符 的 txt 文件导入化学品列表 NO FORMULA NAME CAS No A B C D TMIN TMAX code ngas TMIN ngas 25 C ngas TMAX 1 CBrClF2 brom
  • 如何在函数声明中声明 C++ mem_fn(member_function) ?

    我理解将成员函数的地址传递到类之外的基本问题 我感觉 mem fn 可能是解决方案 但我在具体细节上遇到了麻烦 我在类 p 中有一个成员函数 当前声明为 typedef void valNamedFlagsCallback const in
  • 创建半透明或透明窗口从透明到鼠标事件,添加到表单的控件除外

    您好 我试图获得像玻璃一样的透明形式 它可以使点击和每个鼠标事件传递到玻璃后面的窗口或项目 这是我用 Windows 窗体编写的代码 namespace ClickThroughMe public partial class ClickTh
  • 错误 1 ​​无法将类型“double”隐式转换为“int”。存在显式转换(您是否缺少转换?)[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我的 C 代码有一个错误 他们说 错误 1 无法将类型 double 隐式转换为 int 存在显式转换 是否缺少强制转换 错误在哪
  • 何时在 Java 中使用“this”

    我为我的琐碎且可能愚蠢的问题道歉 但我对在使用方法或访问某些内容时何时使用 this 前缀感到有点困惑 例如 如果我们看 4 这里 http apcentral collegeboard com apc public repository
  • 按钮和 GLSurfaceView

    我有一个 GLSurfaceView 我在其中使用 OpenGL 显示一些动画 我现在想向该视图添加一个按钮 这是如何实现的 不涉及xml布局可以做到吗 您可以手动构建视图并将其添加到活动的内容视图中 在 GLSurfaceView 上执行
  • 从 RDF 节点拉出字符串

    在使用 Jena 的 SPARQL 查询时 我试图以更易读的格式获取数据 但是我不知道如何以正确的方式提取数据 就目前而言 输出是 http www w3 org TR 2003 PR owl guide 20031209 wine Sau
  • 错误:增强禁用线程

    我的 boost 库有一些问题 我正在使用 freebsd 并使用 ports 安装了我的 boost Boost 版本是 1 45 我使用 g 47 作为编译器 另外 我从未在那里定义过 BOOST DISABLE THREADS usr
  • PHP json_decode 表示法问题

    我在处理我尝试解析的 JSON 文件中使用的符号时遇到问题 一些节点有 句点 在转义对象表示法的名称中 json article gt rssFeed url 我将如何选择节点 我是否需要 str replace 句点 或者是否可以使用其他
  • 如何通过 Xcode Designer 添加 MPVolumeView?

    我最初将 MPVolumeView 动态添加到页面上 import MediaPlayer MPVolumeView h IBAction handleVolumeButtonClicked id sender if volumeView
  • 这个 C++ 程序有什么问题?

    当我编译这个程序时 include
  • ROCKSDB 由于rocksdb_max_row_locks 无法获取锁

    我尝试将 CSV 加载到 Rocksdb 数据库中 但失败并显示以下错误 Got error 10 Operation aborted Failed to acquire lock due to rocksdb max row locks
  • 图像尺寸(drawable-hdpi/ldpi/mdpi/xhdpi)

    研究android 现在我有一些图像要放入可绘制目录 hdpi ldpi mdpi xhdpi 中 我读了很多 但我还是不明白 每个目录的图像尺寸应该是多少 希望这会有所帮助 mdpi 是参考密度 也就是说 mdpi 显示屏上的 1 像素等
  • 如何在引导模式上设置本地存储?

    modal 2 id 打开调查模式 我想要的只是这个特定的模式 在有人单击关闭按钮后每 24 小时重新出现一次 document ready function var modals events if window location has
  • 类型声明之前的问号(?)在php(?int)中意味着什么[重复]

    这个问题在这里已经有答案了 我在中看到过这段代码https github com symfony symfony blob master src Symfony Component Console Output Output php htt
  • 以编程方式添加项目引用

    基本上 在阅读了几个链接后 我尝试了上面的代码 foreach EnvDTE Project proj in soln Projects if proj Name BLL VSLangProj VSProject vsproj VSLang
  • Apple Mach-O 链接器错误 lxml

    我刚刚将 xcode 升级到 4 5 现在编译时出现错误 ld library not found for lxml2 2 7 3 cland error linker command failed with exit code 1 升级后
  • 窗口函数或公共表表达式:计算范围内的前几行

    我想使用窗口函数来确定每一行满足特定条件的先前记录的总数 一个具体的例子 clone d test Table pg temp 2 test Column Type Modifiers id bigint date timestamp wi