在Postgres中为每个用户选择每个第N行

时间:2011-09-22 17:14:23

标签: sql postgresql select window-functions row-number

我正在使用这个SQL语句:

SELECT "dateId", "userId", "Salary" 
FROM (
   SELECT *, 
          (row_number() OVER (ORDER BY "userId", "dateId"))%2 AS rn 
   FROM user_table
 ) sa 
 WHERE sa.rn=1 
   AND "userId" = 789 
   AND "Salary" > 0;

但每次表格获得新行时,查询结果都不同 我错过了什么吗?

3 个答案:

答案 0 :(得分:5)

假设("dateId", "userId")是唯一的,而新行总是有更大的(稍后的)dateId

经过一些评论后:

认为你需要什么:

SELECT "dateId", "userId", "Salary"
FROM (
   SELECT "dateId", "userId", "Salary"
         ,(row_number() OVER (PARTITION BY "userId"   -- either this
                              ORDER BY "dateId")) % 2 AS rn
   FROM   user_table
   WHERE  "userId" = 789                              -- ... or that
   ) sub
WHERE  sub.rn = 1
AND    "Salary" > 0;

注意PARTITION BY。这样,您可以为每个dateId跳过每秒userId,而其他(稍后的)行到目前为止不会更改选择。

此外,只要您为 userIdWHERE "userId" = 789)选择行,请将谓词拉入子查询,实现相同的效果(单个用户的稳定选择)。你不需要两者。

子查询中的WHERE子句仅适用于单个用户,PARTITION BY适用于一个查询中的任意数量的用户。

是吗?是吗?
他们应该给我“侦探”徽章。
<子>严重。

答案 1 :(得分:0)

不,这似乎没问题。 您有新行,这些行会在排序后更改旧行以显示在不同位置。

答案 2 :(得分:0)

如果有人插入一个userId低于789的新行,则订单会发生变化。 例如,如果您有:

userId rn
 1      1
 4      0
 5      1
 6      0

并且你插入一行userId = 2,rn将改变:

userId rn
 1      1
 2      0
 4      1
 5      0
 6      1

为了选择每个第N行,您需要一个带有序列或时间戳的列。