不使用日期时间或 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 的 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
我有一个基本的 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 的 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