Tsql 按顺序使用“选择顶部”和“删除顶部”是否安全?
我经常在升级脚本中编写这样的T-SQL循环:Tsql 按顺序使用“选择顶部”和“删除顶部”是否安全?,tsql,Tsql,我经常在升级脚本中编写这样的T-SQL循环: While Exists (Select * From #MyTable) Begin Declare @ID int, @Word nvarchar(max) Select Top 1 @ID=ID, @Word=[Word] From #MyTable -- Do something -- Delete #MyTable Where ID=@ID End 虽然效果不错,但我注意到新的Delete
While Exists (Select * From #MyTable)
Begin
Declare @ID int, @Word nvarchar(max)
Select Top 1 @ID=ID, @Word=[Word] From #MyTable
-- Do something --
Delete #MyTable Where ID=@ID
End
虽然效果不错,但我注意到新的Delete Top函数在#MyTable只是一个字符串列表时非常有用。在这种情况下,这是否有效:
While Exists (Select * From #MyTable)
Begin
Declare @Word nvarchar(max)
Select Top 1 @Word=[Word] From #MyTable
-- Do something --
Delete Top(1) #MyTable
End
是的,它在我的测试脚本中起作用,但这安全吗?将选择Top 1并删除Top(1)始终引用同一条记录,或者Top有点模糊
谢谢你,Rob。如果你经常写循环,要么是你做错了什么,要么是你的数据库需要重新设计,要么是你插入了大量的数据,这些数据需要以1000条左右的记录批量运行。我敢打赌,您正在做的几乎所有事情都可以以基于集合的方式完成,并极大地提高性能。如果不知道在做某件事时会发生什么情况,我无法向您演示如何进行设置,但很可能可以使用case startement进行设置。如果您经常编写循环,则可能是您做错了什么,或者您的数据库需要重新设计,或者您插入了大量数据,这些数据需要以大约1000条记录的批次运行。我敢打赌,您正在做的几乎所有事情都可以以基于集合的方式完成,并极大地提高性能。如果不知道在做某件事时会发生什么情况,我无法向您演示如何进行设置,但很可能可以使用case startement进行设置。不,您的第二个示例不安全 如果您要使用“选择顶部…”(并且您关心行的选择顺序),那么您应该真正使用“order BY”来明确指定顺序。如果不使用“order BY”,您可能会获得所需的订单,但如果不使用order BY,SQL Server不会保证返回行的顺序
在“DELETE TOP..”的情况下,您不能添加“ORDER BY”,因此您应该使用WHERE子句唯一地标识要删除的行,就像您在第一个示例中所做的那样 不,您的第二个示例不安全 如果您要使用“选择顶部…”(并且您关心行的选择顺序),那么您应该真正使用“order BY”来明确指定顺序。如果不使用“order BY”,您可能会获得所需的订单,但如果不使用order BY,SQL Server不会保证返回行的顺序
在“DELETE TOP..”的情况下,您不能添加“ORDER BY”,因此您应该使用WHERE子句唯一地标识要删除的行,就像您在第一个示例中所做的那样 在这种情况下,您可以使用OUTPUT语句,您不需要像这样使用OUTPUT命令:
DELETE #Origin_table
OUTPUT deleted.* INTO #Loop_Work
完整示例:
--DROP TABLE #Origin_table, #Loop_Work
CREATE TABLE #Origin_table (I INT IDENTITY, N VARCHAR(100))
INSERT #Origin_table VALUES
('Test A'), ('Test B'), ('Test C')
, ('Test D'), ('Test E'), ('Test F')
, ('Test G'), ('Test H'), ('Test I')
CREATE TABLE #Loop_Work (I INT, N VARCHAR(100))
WHILE EXISTS (SELECT TOP 1 1 FROM #Origin_table) BEGIN
TRUNCATE TABLE #Loop_Work --> Clear faster our table for loop
DELETE TOP (3) #Origin_table --> Delete top records
OUTPUT deleted.* INTO #Loop_Work --> Use the same records as OUTPUT and insert into the #Loop_Work
--> The OUTPUT statement works similar as a trigger --> It's safe!
SELECT * FROM #Loop_Work --> Do what you need
END
如果要订购,请在删除中使用:
TRUNCATE TABLE #Loop_Work
;WITH To_Delete AS ( --Remember the semicolon
SELECT TOP 3 *
FROM #Origin_table
ORDER BY I DESC
)
DELETE To_Delete --And use the CTE
OUTPUT deleted.* INTO #Loop_Work
在这种情况下,您可以使用OUTPUT语句,您不需要像这样使用OUTPUT命令:
DELETE #Origin_table
OUTPUT deleted.* INTO #Loop_Work
完整示例:
--DROP TABLE #Origin_table, #Loop_Work
CREATE TABLE #Origin_table (I INT IDENTITY, N VARCHAR(100))
INSERT #Origin_table VALUES
('Test A'), ('Test B'), ('Test C')
, ('Test D'), ('Test E'), ('Test F')
, ('Test G'), ('Test H'), ('Test I')
CREATE TABLE #Loop_Work (I INT, N VARCHAR(100))
WHILE EXISTS (SELECT TOP 1 1 FROM #Origin_table) BEGIN
TRUNCATE TABLE #Loop_Work --> Clear faster our table for loop
DELETE TOP (3) #Origin_table --> Delete top records
OUTPUT deleted.* INTO #Loop_Work --> Use the same records as OUTPUT and insert into the #Loop_Work
--> The OUTPUT statement works similar as a trigger --> It's safe!
SELECT * FROM #Loop_Work --> Do what you need
END
如果要订购,请在删除中使用:
TRUNCATE TABLE #Loop_Work
;WITH To_Delete AS ( --Remember the semicolon
SELECT TOP 3 *
FROM #Origin_table
ORDER BY I DESC
)
DELETE To_Delete --And use the CTE
OUTPUT deleted.* INTO #Loop_Work
+1,循环+数据库=慢。但是,OP没有使用光标!我从没说过他是。但他所做的很有可能是以一种基于集合的方式完成的。对不起,我应该澄清一下“我经常在升级脚本中编写循环”。。。在实际的应用程序中永远不会做这样的事情+1,循环+数据库=慢。但是,OP没有使用光标!我从没说过他是。但他所做的很有可能是以一种基于集合的方式完成的。对不起,我应该澄清一下“我经常在升级脚本中编写循环”。。。在实际的应用程序中永远不会做这样的事情!谢谢,我有点怀疑是这样的。谢谢,我有点怀疑是这样的。