不使用日期时间或 ID 删除 SQL 服务器中的最新条目

Delete latest entry in SQL Server without using datetime or ID

我有一个基本的 SQL 服务器删除脚本:

Delete from tableX 
where colA = ? and colB = ?;

tableX中,我没有任何指示顺序ID或时间戳的列;只是 varchar。我想删除插入的最新条目,但我无权从插入脚本访问行号。 TOP 不是一个选项,因为它是随机的。此外,这个特定的 table 没有主键,这不是设计不佳的问题。有什么办法可以做到这一点?我记得 mysql 可以调用 max(row_number) 之类的东西,也可以调用 limit one 之类的东西。

ROW_NUMBER 也存在于 SQL 服务器中,但必须与 OVER (order_by_clause) 一起使用。所以......在你的情况下,除非你想出另一种排序算法,否则这对你来说是不可能的。

MSDN

编辑:(来自 MSDN 的 George 的示例...恐怕他的公司有阻止 MSDN 的防火墙规则)

SQL-代码

USE AdventureWorks2012; 
GO
SELECT ROW_NUMBER() OVER(ORDER BY SalesYTD DESC) AS Row, 
    FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD" 
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0;

输出

Row FirstName    LastName               SalesYTD
--- -----------  ---------------------- -----------------
1   Linda        Mitchell               4251368.54
2   Jae          Pak                    4116871.22
3   Michael      Blythe                 3763178.17
4   Jillian      Carson                 3189418.36
5   Ranjit       Varkey Chudukatil      3121616.32
6   José         Saraiva                2604540.71
7   Shu          Ito                    2458535.61
8   Tsvi         Reiter                 2315185.61
9   Rachel       Valdez                 1827066.71
10  Tete         Mensa-Annan            1576562.19
11  David        Campbell               1573012.93
12  Garrett      Vargas                 1453719.46
13  Lynn         Tsoflias               1421810.92
14  Pamela       Ansman-Wolfe           1352577.13

返回行的子集

USE AdventureWorks2012;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
    FROM Sales.SalesOrderHeader 
) 
SELECT SalesOrderID, OrderDate, RowNumber  
FROM OrderedOrders 
WHERE RowNumber BETWEEN 50 AND 60;

将 ROW_NUMBER() 与 PARTITION

结合使用
USE AdventureWorks2012;
GO
SELECT FirstName, LastName, TerritoryName, ROUND(SalesYTD,2,1),
ROW_NUMBER() OVER(PARTITION BY TerritoryName ORDER BY SalesYTD DESC) AS Row
FROM Sales.vSalesPerson
WHERE TerritoryName IS NOT NULL AND SalesYTD <> 0
ORDER BY TerritoryName;

输出

FirstName  LastName             TerritoryName        SalesYTD      Row
---------  -------------------- ------------------   ------------  ---
Lynn       Tsoflias             Australia            1421810.92    1
José       Saraiva              Canada               2604540.71    1
Garrett    Vargas               Canada               1453719.46    2
Jillian    Carson               Central              3189418.36    1
Ranjit     Varkey Chudukatil    France               3121616.32    1
Rachel     Valdez               Germany              1827066.71    1
Michael    Blythe               Northeast            3763178.17    1
Tete       Mensa-Annan          Northwest            1576562.19    1
David      Campbell             Northwest            1573012.93    2
Pamela     Ansman-Wolfe         Northwest            1352577.13    3
Tsvi       Reiter               Southeast            2315185.61    1
Linda      Mitchell             Southwest            4251368.54    1
Shu        Ito                  Southwest            2458535.61    2
Jae        Pak                  United Kingdom       4116871.22    1

您当前的 table 设计不允许您确定最新条目。您没有要排序的字段来指示最后添加的记录。

您需要重新设计或从审计 table 中提取该信息。如果您的数据库没有审计 tables,您可能必须找到一个工具来读取事务日志,这将是一个非常耗时且昂贵的过程。或者,如果您知道添加要删除的记录的日期,则可以使用恰好在此之前的备份来查找添加的记录。请注意,您可能正在查看在您想要保留的该日期之后更改的记录。

如果您需要定期执行此操作而不是一次性修复一些错误数据,那么您需要正确设计您的数据库以包含身份字段和可能的日期更新字段(通过触发器维护)或审核 tables。 (在我看来,包含贵公司所依赖的信息的数据库不应该没有审计 tables,这是你永远不应该允许 ORM 设计数据库的众多原因之一,但我离题了。)如果你需要知道订单记录已添加到 table,作为开发人员,您有责任创建该结构。数据库只存储设计用来存储的内容,如果你没有设计它,那么它就不容易或根本不可用

如果(colA +'_'+ colB)无法重复,试试这个。

 declare @delColumn nvarchar(250)

    set @delColumn = (select top 1   DeleteColumn from (
    select (colA +'_'+ colB)  as DeleteColumn ,
          ROW_NUMBER() OVER(ORDER BY colA DESC) as Id from tableX  
    )b
    order by Id desc
    )

delete  from tableX where  (colA +'_'+ colB) =@delColumn