-1

我写了一个需要重写的 SQL 查询。基本上,它做了这样的事情:

select log_number, 
    code_id, 
    code_name, 
    ... 
    buyer_id,
    ...
    rank() over (
        partition by code_id, buyer_id 
        order by (date_trunc('second',cdr.dateconso) - date_trunc('second',log.datecrea)) asc
        ) as ranking,
from ...
join ... on ...
left join ... on ...
join ...
where ...

它与 PostgreSQL 的最新版本完美配合。

但是,以下指令:

rank() over (
    partition by code.blg_promocode_keyid, cdr.tph_wp_account_buyer_keyid 
    order by (date_trunc('second',cdr.dateconso) - date_trunc('second',log.datecrea)) asc
    ) as ranking,

...使用当前安装的 PostgreSQL 版本生成语法错误,我必须找到绕过它的解决方案,但我不知道。

错误:查询失败:错误:“over”处或附近的语法错误第 21 行:rank() over (partition by ...

4

1 回答 1

1

这可能是微不足道的..

select log_number,
   ...
   rank() over (
        partition by code_id, buyer_id 
        order by (date_trunc('second',cdr.dateconso)
                - date_trunc('second',log.datecrea))
        ) as ranking,
from ...

..如果您实际上在最后一项之后有一个逗号SELECT(您不应该这样做)。

.. 或不

正如稍后的评论中所阐明的,目标是在没有窗口函数的旧版本 PostgreSQL 中进行模拟- 版本 8.2 或更早版本。rank()

真正应该做的是升级到具有窗口函数的更新版本(PostgreSQL 8.4 或更高版本)。PostgreSQL 8.2 已于 2011 年 12 月终止

除此之外,您可以在 PostgreSQL 8.2rank()中借助临时序列临时表、一些子查询聚合函数进行模拟。但这并不漂亮:

测试设置(从您的示例中简化)

CREATE TEMP TABLE t(code_id int, buyer_id int, the_date date);
INSERT INTO t  VALUES
 (1, 1, '2012-08-01')
,(1, 1, '2012-08-01')
,(1, 1, '2012-08-01')
,(1, 1, '2012-08-02')
,(1, 1, '2012-08-03')
,(1, 1, '2012-08-04')
,(2, 3, '2012-09-01')
,(2, 3, '2012-09-02')
,(2, 3, '2012-09-02')
,(2, 3, '2012-09-02')
,(2, 3, '2012-09-04')
,(2, 3, '2012-09-06');

我使用临时表多次重用结果。在现代 PostgreSQL 中,您将改用 CTE。临时序列充当与相关
的穷人的替代品。要按您想要的所有列获取基本行号顺序-按该顺序:row_number()nextval()PARTITION BYORDER BYrank()

CREATE TEMP SEQUENCE t_seq;  -- once per session ..
-- SELECT setval('t_seq', 1, FALSE); --  .. or reset for repeated use

-- DROP TABLE tmp; 
CREATE TEMP TABLE tmp AS     -- once per session or drop first
SELECT code_id
      ,buyer_id
      ,the_date
      ,nextval('t_seq') AS rownum
       -- rank() included to compare results in modern version
       -- remove this line in old version:
      ,rank() OVER (PARTITION BY code_id, buyer_id ORDER BY the_date) AS rnk
FROM   t
ORDER  BY code_id, buyer_id, the_date;

你也可以编写一个像Depesz 在这里演示C的语言函数......

现在,获取rownum每个对等组的最小值(子查询peer)并减去rownum每个组的最小值(子查询grp)以获得实际的行号:

SELECT t.*, peer.rn - grp.rn AS rnk_8_2
FROM   tmp t
JOIN (
   SELECT code_id, buyer_id, min(rownum) -1 AS rn
   FROM   tmp
   GROUP  BY code_id, buyer_id
   ) grp USING (code_id, buyer_id)
JOIN (
   SELECT code_id, buyer_id, the_date, min(rownum) AS rn
   FROM   tmp
   GROUP  BY code_id, buyer_id, the_date
   ) peer USING (code_id, buyer_id, the_date)
ORDER BY code_id, buyer_id, the_date;

瞧。rnk_8_2匹配rnk

清理(​​或让对象在会话结束时被丢弃):

DROP SEQUENCE t_seq;
DROP TABLE t, tmp; 

请注意,您必须为每个会话/执行创建/重置/重新创建临时对象。
在 PostgreSQL 9.1 中测试,但应该在 8.2 中工作。

于 2012-09-21T10:34:32.950 回答