【问题标题】:Syntax error near rank() functionrank() 函数附近的语法错误
【发布时间】:2012-09-21 08:39:09
【问题描述】:

我写了一个需要重写的 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 ...

【问题讨论】:

  • 和“当前安装的postgreSQL”是什么?如果它是 8.3 或更高版本,则不支持窗口功能,您需要 8.4 或更高版本。否则,请显示整个未编辑的 SQL 语句,因为语法错误可能更早。
  • 您写了关于“PostgreSQL 的最新版本”的文章,但仍然对正在运行的版本保密?你在嘲笑我们吗?
  • 我在 pg 9.0 上编写并运行我的查询,而另一台机器运行不支持窗口功能的 8.2。很抱歉给您延迟了这些信息。
  • 8.2 不受支持。您真的应该将该机器升级到当前版本。
  • 完全同意,即使我不能这样做,因为升级 postgres 不是 我的 工作(但我绝对要求它!)

标签: sql postgresql syntax-error window-functions


【解决方案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。
临时序列充当了与nextval()相关的row_number()的穷人替代品。要获得所有列的基本行号顺序,您将为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;

您还可以编写语言 C 函数,例如 Depesz demonstrates here ...

现在,获取每个对等组的最小值 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 中工作。

【讨论】:

  • 谢谢。但实际上我问的是如何绕过窗口函数,以便查询可以在 8.2 上运行(即使一开始并不清楚。)
  • @sabrina:对于过时的 8.2 版本,您正在寻找的东西并非易事。我添加了一个可能的解决方案。
  • 非常感谢 Erwin 提供的 rank() 仿真操作方法。我会尝试,但无论如何我都会尝试升级软件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 2022-01-28
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
  • 1970-01-01
  • 2013-06-22
相关资源
最近更新 更多