rank()函数附近的语法错误

时间:2012-09-21 08:39:10

标签: sql postgresql syntax-error window-functions

我编写了一个需要重写的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版本生成语法错误,我必须找到绕过它的解决方案,但我不知道。

  

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

1 个答案:

答案 0 :(得分: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 中模拟rank() - 版本8.2或更早版本。

应该做的是升级到具有窗口功能的更新版本(PostgreSQL 8.4或更高版本)。 PostgreSQL 8.2 has reached end-of-life in Dec.2011

除此之外,您可以借助临时序列临时表,某些子查询来模拟rank() PostgreSQL 8.2中的聚合函数。但它并不漂亮:

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

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 BY rank()所有列的基本行号顺序,请按顺序获取:

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 demonstrates here等语言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;

VOILÀ。 rnk_8_2匹配rnk

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

DROP SEQUENCE t_seq;
DROP TABLE t, tmp; 

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