【问题标题】:PostgreSQL lead() issue with camelCase columncamelCase 列的 PostgreSQL lead() 问题
【发布时间】:2016-09-15 16:24:29
【问题描述】:

所以我想查询一个结构是这样的考勤表

employeeId | clockInTime| clockOutTime
-----------+------------+--------------
   555     | 1462797450 | 1462785465 
   555     | 1462883850 | 1462871850 
   111     | 1463056650 | 1463044650 <== skip this
   555     | 1463143050 | 1463131050 <== get this
   555     | 1463229426 | 1463245655 <== but not this

我要做的是选择两个值之间的所有行,但也选择该员工的那组行之后的下一行,无论值如何

这是我的查询

select "clockInTime", "clockOutTime", lead("clockInTime",1)
from "timeCard"
where "clockInTime" between 1462797450 and 1462883850
and "employeeId" = 555

但我收到此错误:

错误:函数前导(bigint,整数)不存在

但是当我从lead() 中删除双引号时,我最终只会得到这个,因为我的列名是驼峰式:

错误:“时钟时间”列不存在

我正在使用 node.js 和 node-pg 客户端。

【问题讨论】:

    标签: sql node.js postgresql node-postgres


    【解决方案1】:

    您没有“lead()中删除双引号”。错误消息显示您实际上删除了 "clockInTime" 中的双引号:

    error: column "clockintime" does not exist
    

    考虑:

    长与短:如果可以避免,请勿在 Postgres 中使用 caMelCase 标识符:


    至于你描述的任务:

    选择两个值之间的所有行,但也选择该员工的该组行之后的下一行

    窗口函数lead() 中缺少OVER 子句,就像@Gordon 指出的那样。但即使修复了语法错误,lead()(或任何其他窗口函数)似乎也不是获得所需内容的正确方法。它为结果中的每一行添加一列,而您想将 row 添加到集合中。

    我建议UNION ALLORDER BY / LIMIT 1 将“下一个”行添加到结果集中:

    SELECT *
    FROM   "timeCard"
    WHERE  "employeeId" = 555
    AND    "clockInTime" BETWEEN 1462797450 AND 1462883850
    
    UNION ALL
    (  -- parentheses required
    SELECT *
    FROM   "timeCard"
    WHERE  "employeeId" = 555
    AND    "clockInTime" > 1462883850
    ORDER  BY "clockInTime"
    LIMIT  1
    );
    

    ("employeeId", "clockInTime") 上的多列 索引 可以使这个速度非常快,即使对于大表也是如此。

    如果"clockInTime" 未定义唯一,您可能需要向ORDER BY 添加更多表达式,以便在出现平局时获得确定性结果。

    需要括号将LIMITORDER BY 添加到UNION 查询的单个分支。示例:

    如果您还希望对前导行进行排序:

    (
    SELECT *
    FROM   "timeCard"
    WHERE  "employeeId" = 555
    AND    "clockInTime" BETWEEN 1462797450 AND 1462883850
    ORDER  BY "clockInTime"
    )
    UNION ALL
    (
    SELECT *
    FROM   "timeCard"
    WHERE  "employeeId" = 555
    AND    "clockInTime" > 1462883850
    ORDER  BY "clockInTime"
    LIMIT  1
    );
    

    【讨论】:

    • 我明白了,谢谢,我使用 camelCase 的原因是因为我希望在整个服务器和前端保持一致。
    • @Darkrum:注意我添加的括号。
    【解决方案2】:

    您需要over 子句。我不确定您到底在寻找什么逻辑,但类似于:

    select "clockInTime", "clockOutTime",
           lead("clockInTime", 1) over (order by clickInTime)
    from "timeCard"
    where "clockInTime" between 1462797450 and 1462883850 and "employeeId" = 555;
    

    通常,您希望每位员工都这样做:

    select "clockInTime", "clockOutTime",
            lead("clockInTime", 1) over (partition by "employeeid" order by clickInTime)
    from "timeCard"
    where "clockInTime" between 1462797450 and 1462883850 and "employeeId" = 555;
    

    【讨论】:

    • 不,我在做那个错误时得到了这个:在“over”处或附近出现语法错误
    • 不是可选的吗?
    • 不,因为导致它是一个窗口函数。
    • @Darkrum 。 . .你确定你使用的是 Postgres?
    • 是的,虽然它是旧版本 8.0.2,因为我们正在针对 aws redshift 进行开发。
    猜你喜欢
    • 2021-08-19
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多