【问题标题】:Selecting every Nth row per user in Postgres在 Postgres 中为每个用户选择每第 N 行
【发布时间】:2011-11-23 01:03:47
【问题描述】:

我正在使用这个 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;

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

【问题讨论】:

  • 您需要告诉我们您想要做什么以及“新行”是什么样的,尤其是您在窗口函数中用于 ORDER BY 的“userId”和“dateId”。
  • 我想优化此查询以在每次更新表时给我相同的结果。 dateId - 只是日期的十进制表示
  • Changed "dateId" 改变了窗口函数中的排序顺序。因此,结果会发生变化。
  • 如何避免这种情况?我在想在表格底部添加“dateId”不应该影响排序顺序......

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


【解决方案1】:

假设("dateId", "userId") 是唯一的,并且新行总是有一个更大的(后来的)dateId

经过一些cmets:

认为你需要什么:

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。这样一来,对于每个 userId,您每秒跳过一次 dateId,并且到目前为止,其他(稍后)行不会更改选择。

另外,只要您为 single userId (WHERE "userId" = 789) 选择行,将谓词拉入子查询,达到相同的效果(单个用户的稳定选择)。两者都不需要。

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

是这样吗?是吗?
他们应该为此给我“侦探”徽章。
说真的。

【讨论】:

  • 感谢您的回复。我的“dateId”是一个外键(唯一)。我将尝试一些“sequenceId”,但怀疑它会有所作为
  • "dateId" 在被引用的表中可能是唯一的,但在 user_table 中仍然可以被多次引用。你知道这一点,对吧?试试我的骗子小测试,你就知道了。
  • 我运行测试并没有得到任何结果。我创建表的方式是特定用户+特定日期只能在数据库中存在一次
  • @TimGL:你能告诉我这段代码背后的意图是什么吗:(row_number() OVER (ORDER BY "userId", "dateId"))%2 AS rn ... WHERE sa.rn=1我建议你用这些信息编辑你的问题。我怀疑我可以解决您的问题,一旦我了解了这应该实现的目标。另外,我仍然想知道我对“userId”的假设是否正确(请参阅我的回答开头)。
  • Brandstetter:您对“userId”的看法是正确的——它是增量的。
【解决方案2】:

如果有人插入用户 ID 低于 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 行,您需要一个带有序列或时间戳的列。

【讨论】:

  • 这是我的表:“dateId”、“userId”、“Salary”,每天我都用新的日期(序列、十进制)更新表,userId 保持不变,Salary 发生变化: - 15234, 789, 32 - 15237, 789, 35 - 15238, 789, 36 dateId - 是一个序列,但不包括周末和节假日。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多