微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sql – 如何在窗口函数中使用环形数据结构

我有数据以环形结构(或 circular buffer)排列,也就是说它可以表示为循环的序列:…- 1-2-3-4-5-1-2-3 -….查看此图片以了解5部分戒指:

我想创建一个窗口查询,可以将滞后和铅项目组合成一个三点数组,但我无法弄明白.例如,在5部分环的第1部分,滞后/超前序列是5-1-2,或者部分4是3-4-5.

以下是两个具有不同数量部件的环的示例表(每个环总是多于三个):

create table rp (ring int,part int);
insert into rp(ring,part) values(1,generate_series(1,5));
insert into rp(ring,part) values(2,7));

这是一个几乎成功的查询

SELECT ring,part,array[
    lag(part,1,NULL) over (partition by ring),lead(part,1) over (partition by ring)
    ] AS neighbours
FROM rp;

 ring | part | neighbours
------+------+------------
    1 |    1 | {NULL,2}
    1 |    2 | {1,2,3}
    1 |    3 | {2,3,4}
    1 |    4 | {3,4,5}
    1 |    5 | {4,5,1}
    2 |    1 | {NULL,2}
    2 |    2 | {1,3}
    2 |    3 | {2,4}
    2 |    4 | {3,5}
    2 |    5 | {4,6}
    2 |    6 | {5,6,7}
    2 |    7 | {6,7,1}
(12 rows)

我唯一需要做的就是用每个环的终点替换NULL,这是最后一个值.现在,随着lag and lead window functions,there is a last_value function这将是理想的.但是,这些不能嵌套:

SELECT ring,last_value(part) over (partition by ring)) over (partition by ring),1) over (partition by ring)
    ] AS neighbours
FROM rp;
ERROR:  window function calls cannot be nested
LINE 2:     lag(part,last_value(part) over (partition by ring)) ...

更新.感谢@ Justin建议使用coalesce来避免嵌套窗口函数.此外,许多人已经指出,第一个/最后一个值需要通过环序列的明确顺序,这恰好是该示例的一部分.所以稍微随机化输入数据:

create table rp (ring int,part) select 1,5) order by random();
insert into rp(ring,part) select 2,7) order by random();

解决方法

>像 @Justin provided一样使用 COALESCE.
>使用first_value()/ last_value(),您需要向窗口定义添加ORDER BY子句,或者未定义顺序.你刚才在这个例子中很幸运,因为在创建虚拟表之后,这些行恰好按顺序排列.
添加ORDER BY后,认窗口框架将在当前行结束,您需要特殊情况下调用last_value() – 或者在窗口框架中恢复排序顺序,如我的第一个示例中所示.
>多次重用窗口定义时,显式的WINDOW子句简化了语法:
SELECT ring,ARRAY[
          coalesce(
             lag(part) OVER w,first_value(part) OVER (PARTITION BY ring ORDER BY part DESC)),coalesce(
             lead(part) OVER w,first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring ORDER BY part);

更好的是,重用相同的窗口定义,因此Postgres可以在单次扫描中计算所有值.为此,我们需要定义一个自定义窗口框架:

SELECT ring,last_value(part) OVER w),first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring
             ORDER BY part
             RANGE BETWEEN UNBOUNDED PRECEDING
                       AND UNBOUNDED FOLLOWING)
ORDER  BY 1,2;

您甚至可以调整每个窗口函数调用的帧定义:

SELECT ring,last_value(part) OVER (w RANGE BETWEEN CURRENT ROW
                                                AND UNBOUNDED FOLLOWING)),first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring ORDER BY part)
ORDER  BY 1,2;

对于具有许多部件的环,可能会更快.你必须测试.

SQL Fiddle展示了所有三个改进的测试用例.考虑查询计划.

有关窗框定义的更多信息:

> In the manual.
> PostgreSQL window function: partition by comparison
> PostgreSQL query with max and min date plus associated id per row

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_no='LJCG001H' THEN dbo.ELTPNAME(a.fw_nu) ELSE d.fm_name END),e.fw_state_nm,f.fw_rmk_nm
if not exists(select name from syscolumns where name='tod_no' and id=object_id('iebo09d12')) alter table iebo09d12 add tod_no varchar(
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_nm,g.fa_name from LJSS007H a (nolock) Left join LJPA002H b (nolock) On a.pa_no =b.pa_no Left jo
要在 SQL Server 2019 中设置定时自动重启,可以使用 Windows 任务计划程序。下面是详细的步骤: 步骤一:创建批处理文件 打开记事本。 输入以下内容: net stop "SQL Server (MSSQLSERVER)" net start "SQ
您收到的错误消息表明数据库 'EastRiver' 的事务日志已满,导致数据库操作失败。要解决这个问题,可以按照以下步骤操作: 1. 备份事务日志首先,备份事务日志以释放空间: BACKUP LOG [EastRiver] TO DISK = N'C:\Backup\East
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标识ID,若不知道怎么查询数据库的标识ID, 打开SQL Server management studio,点击工具。选择SQL Server Profiler。 登录,登录成功后,如果有个默认弹窗,先取消 新建追踪 命名
--最新的解决方法 --先创建用户帐户,不进行授权,然后通过下面的SQL语句将该用户帐户关联至对应的数据库用户。优点是避免了重新授权的操作。 USE tempdbEXEC sp_change_users_login 'Update_One', 'iemis', &#3
命令: ALTER TABLE 表名 add 列名 数据类型 default 默认值 not null 例如: ALTER TABLE LJEL005H add el_req int default 15 not null
declare @i int set @i=340 while @i<415 begin set @i=@iʱ insert into LJWK007H select '2024','28','9110','3PTSD621000000