【问题标题】:sqlite equivalent of row_number() over ( partition by ...?sqlite 相当于 row_number() over ( partition by ...?
【发布时间】:2010-11-02 01:03:50
【问题描述】:

我想知道是否可以使用单个 sqlite 语句执行以下操作:

我的桌子看起来像这样:

|AnId|UserId|SomeDate|SomeData|
|123 |A     |1/1/2010|aadsljvs|
| 87 |A     |2/9/2010|asda fas|
|193 |A     |2/4/2010|aadsljvs|
|927 |A     |7/3/2010|aadsasdf|
|816 |B     |1/1/2010|aa32973v|
|109 |B     |7/5/2010|aaasfd10|
| 39 |B     |1/3/2010|66699327|
...

每一行都有一个唯一的 id、一个用户 id、一个日期时间值和一些其他数据。

我想删除记录,因此我根据 SomeDate 保留每位用户的最新 10 条记录。

在 sql server 中我会使用这样的东西:

delete d
from data d
inner join (
    select UserId
        ,  AnId
        ,  row_number() over ( partition by UserId order by SomeDate desc ) 
              as RowNum
    from data 
) ranked on d.AnId = ranked.AnId
where ranked.RowNum > 10

有没有办法在 sqlite 中做到这一点?有几条记录具有相同 SomeDate 的边缘情况并不是特别担心,例如如果我保留所有这些记录就好了。

【问题讨论】:

    标签: sql sqlite


    【解决方案1】:

    我知道这个问题已经过时了,但是下面的 SQLite 语句将执行 Rory 在一个语句中最初要求的内容 - 删除给定 UserId 的所有记录,这些记录不是该 UserId 的 10 条最新记录(基于 SomeDate) .

    DELETE FROM data
    WHERE AnId IN (SELECT AnId
                   FROM data AS d
                   WHERE d.UserId = data.UserId
                   ORDER BY SomeDate DESC
                   LIMIT -1 OFFSET 10)
    

    【讨论】:

    • 太棒了!并且知道我知道OFFSET
    • 我不明白为什么这是原始问题的答案。他想删除所有用户的旧条目,而不仅仅是一个。
    • @Carsten @Jett - 很久以前我不记得测试过这个......它甚至可以使用与data 表相关的IN 子句吗?如果是这样,那么我猜IN 会为每一行单独评估,因此它应该适用于所有用户。但肯定 Jett 的描述不是我想要的,即它不是删除 given UserId 的记录,而是删除所有 UserIds 的记录。这就是让它变得棘手的原因,在 SQL Server 中需要row_number() over ( partition by ... )
    【解决方案2】:

    我需要为与“对象”表具有一对多关系的表中的每个“对象”获取第二行。

    通常在 SQL 中,这将使用 ROW_NUMBER() OVER(PARTITION BY object_id ORDER BY primary_id DESC) 完成

    在 Sqlite 中,我必须想出这个 voodoo 子查询才能获得相同的结果

    SELECT object_id, MAX(_id)
    FROM (SELECT object_id, _id
    FROM aTable
    EXCEPT
    SELECT object_id, MAX(_id)
    FROM aTable
    GROUP BY object_id)
    GROUP BY object_id;
    

    注意:_id是aTable的主键,对象表和查询表是一对多的关系

    【讨论】:

      【解决方案3】:

      如果你还没有得到答案。 如果是一张表,那么您不需要任何连接。您可以使用:

      Delete From data
      where AnId not in (Select AnId
                         from data
                         Order by SomeDate DESC
                         Limit 10)
      

      【讨论】:

        【解决方案4】:

        从 Sqlite 3.25 开始支持窗口函数。 详情请见https://www.sqlite.org/windowfunctions.html

        【讨论】:

          【解决方案5】:

          这可能会非常昂贵(也许只有在用户插入新记录时才这样做?)但是这样怎么样:

          for user in users:
            user-records = select * from records where user=user
            if user-records.length > 10:
              delete from records where user=user and date<user-records[10]
          

          (混合使用 SQL 和伪代码)

          【讨论】:

          • 当然,我可以通过程序来完成,但如果可能的话,我希望有一种方法可以在单个语句中完成。如果按程序进行,也可以为每个用户使用单个语句,并且仅适用于表中有记录的用户
          • 啊,是的;那我就不知道了。出于好奇,如何在每个用户的单个语句中做到这一点?
          • 嗯,这就是问题所在!问题中的语法显示了如何在 sql server 中执行此操作。我不知道这在sqlite中是否可行。我怀疑不是。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-24
          • 1970-01-01
          • 2012-09-23
          • 2020-01-14
          相关资源
          最近更新 更多