【问题标题】:Query to delete records older than n active dates from each group查询从每个组中删除早于 n 个活动日期的记录
【发布时间】:2016-03-04 12:15:28
【问题描述】:

我有一个需要每天修剪的数据集。它由定期将记录写入表的进程填充。

我目前有一个简单的查询:

DELETE FROM dataTable WHERE entryDate < dateadd(day, -5, GETDATE())

但问题是过程不可靠;可能有几天根本没有数据写入。

所以我真正需要的是一个可以追溯到 5 天(可能不连续)写入数据的天,而不是 5 个日历日的查询。

例如,如果我运行以下查询:

SELECT cast(entryDate  as date) as LogDate
  FROM dataTable
  group by category, cast(entryDate as date)
  order by cast(entryDate as date) desc

我可能会得到这样的结果:

Category    Date
Foo        2015-11-30
Foo        2015-11-29
Foo        2015-11-26
Foo        2015-11-25
Foo        2015-11-21
Foo        2015-11-20  <-- Start Pruning here, not the 25th.
Foo        2015-11-19
Foo        2015-11-18

Bar        2015-11-30
Bar        2015-11-29
Bar        2015-11-28
Bar        2015-11-27
Bar        2015-11-26
Bar        2015-11-25  <-- This one is OK to prune at the 25th.
Bar        2015-11-24
Bar        2015-11-23

我需要查询一直回到 20 日才被删除。

【问题讨论】:

  • 一种方法是使用子查询来确定“修剪日期”。
  • 为什么不使用Limit? DELETE FROM dataTable WHERE entryDate IN (--your query-- + LIMIT 5)
  • DELETE FROM dataTable WHERE entryDate IN (SELECT cast(entryDate as date) as LogDate FROM dataTable group by anotherField, cast(entryDate as date) order by cast(entryDate as date) desc LIMIT 5)
  • @wajeeh "'LIMIT' 附近的语法不正确

标签: c# sql sql-server tsql sql-server-2012


【解决方案1】:

您可以使用row_number 获取表有条目的最后 5 天。然后根据生成的数字删除。

SQL Fiddle

with rownums as (SELECT row_number() over(partition by category order by cast(entryDate as date) desc) as rn
                 ,*
                 FROM dataTable
)
delete from rownums where rn <= 5 --use > 5 for records prior to the last 5 days

如果每天可以有多个条目,请使用dense_rank 对行进行编号。

with rownums as (SELECT dense_rank() over(partition by category order by cast(entryDate as date) desc) as rn
                     ,*
                 FROM dataTable)
delete from rownums where rn > 5;

【讨论】:

  • 该死,我才意识到我需要先按另一个字段分组。所以最近的 5 个必须在每个组上。
  • 是的,在这种情况下,您可以在row_number 中使用partition by
  • 如果你添加它,我会继续接受(你可以为分区列起一个名字),我会相应地解决我的问题。谢谢,感谢您的帮助。
  • 啊,我刚刚意识到为什么它不应该返回日期......该过程每天可以多次写入表。
  • @RobertHarvey..在这种情况下使用dense_rank()。 dense_rank() over(partition by somecolumn order by cast(entryDate as date) desc)
【解决方案2】:

试试这样的。

;WITH orderedDates (LogDate, RowNum)
AS 
(
SELECT [CACHEDATE] AS LogDate, ROW_NUMBER() OVER (ORDER BY CACHEDATE DESC) AS RowNum
FROM
dataTable
GROUP BY CACHEDATE
)
DELETE dataTable
WHERE CACHEDATE IN
(SELECT LogDate FROM orderedDates
WHERE ROWNUM > 5) --or however many you need to go back

【讨论】:

  • 需要另外一组。对此感到抱歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多