SQL Server:使用ORDER BY更新表

时间:2010-08-09 10:26:03

标签: sql-server

我想知道在更新表时是否有使用order by子句的方法。我正在更新表并设置一个连续的数字,这就是更新顺序很重要的原因。使用以下sql语句,我能够在不使用游标的情况下解决它:

DECLARE @Number INT = 0

UPDATE Test
SET @Number = Number = @Number +1

现在我想要做的是这样的order by子句:

 DECLARE @Number INT = 0

 UPDATE Test
 SET @Number = Number = @Number +1
 ORDER BY Test.Id DESC

我已阅读:How to update and order by using ms sql此问题的解决方案无法解决排序问题 - 它们只是过滤了应用更新的项目。

保重, 马丁

10 个答案:

答案 0 :(得分:51)

没有

没有记录100%支持的方式。有一种方法有时用于计算称为“quirky update”的运行总计,这表明如果满足某些条件,它可能按聚集索引的顺序更新但据我所知,这完全依赖于经验观察而不是任何保证

但是你在使用什么版本的SQL Server?如果SQL2005 +您可以使用row_number和CTE(您可以更新CTE)执行某些操作

With cte As
(
SELECT id,Number,
ROW_NUMBER() OVER (ORDER BY id DESC) AS RN
FROM Test
)
UPDATE cte SET Number=RN

答案 1 :(得分:17)

您不能将ORDER BY用作UPDATE语句的一部分(您可以在作为更新一部分的子选择中使用)。

UPDATE Test 
SET Number = rowNumber 
FROM Test
INNER JOIN 
(SELECT ID, row_number() OVER (ORDER BY ID DESC) as rowNumber
FROM Test) drRowNumbers ON drRowNumbers.ID = Test.ID

答案 2 :(得分:4)

修改

以下解决方案可能会遇到涉及的聚簇索引问题here。感谢Martin指出这一点。

答案是教育那些不了解SQL Server的所有副作用或来龙去脉的人(比如我)。


在您的链接中扩展Quassnoi的答案,继续工作

DECLARE @Test TABLE (Number INTEGER, AText VARCHAR(2), ID INTEGER)
DECLARE @Number INT

INSERT INTO @Test VALUES (1, 'A', 1)
INSERT INTO @Test VALUES (2, 'B', 2)
INSERT INTO @Test VALUES (1, 'E', 5)
INSERT INTO @Test VALUES (3, 'C', 3)
INSERT INTO @Test VALUES (2, 'D', 4)

SET @Number = 0

;WITH q AS (
    SELECT  TOP 1000000 *
    FROM    @Test
    ORDER BY
            ID
)            
UPDATE  q
SET     @Number = Number = @Number + 1

答案 3 :(得分:2)

row_number()函数将是解决此问题的最佳方法。

UPDATE T
    SET T.Number = R.rowNum
    FROM Test T
    JOIN (
        SELECT T2.id,row_number() over (order by T2.Id desc) rowNum from Test T2
    ) R on T.id=R.id 

答案 4 :(得分:2)

基于按SQL IN()子句

中的值顺序排序进行更新

<强>解决方案:

DECLARE @counter int
SET @counter = 0

;WITH q  AS
        (
select * from Products WHERE ID in (SELECT TOP (10) ID FROM Products WHERE  ID IN( 3,2,1) 
ORDER BY ID DESC)
        )
update q set Display= @counter, @counter = @counter + 1

此更新基于降序3,2,1

希望帮助某人。

答案 5 :(得分:1)

我遇到了同样的问题,并且能够以非常强大的方式解决它,允许无限排序的可能性。

我使用(保存)2个排序顺序创建了一个视图(*解释如何在下面这样做)。

之后,我只是将更新查询应用于创建的视图,并且效果很好。

以下是我在视图中使用的2个查询:

第一次查询:

Update  MyView
Set SortID=0


第二次质询:

DECLARE @sortID int
SET     @sortID = 0
UPDATE  MyView
SET     @sortID = sortID = @sortID + 1


*为了能够在View中保存排序,我将TOP放入SELECT语句中。这个非常有用的解决方法允许在打开视图时创建视图时按照设置的方式返回View结果。就我而言,它看起来像:

(注意:如果使用大表,使用此变通方法将在服务器上产生很大的负担,因此如果使用大型表,建议在视图中包含尽可能少的字段)

SELECT     TOP (600000) 
dbo.Items.ID, dbo.Items.Code, dbo.Items.SortID, dbo.Supplier.Date, 
dbo.Supplier.Code AS Expr1
FROM         dbo.Items INNER JOIN
                      dbo.Supplier ON dbo.Items.SupplierCode = dbo.Supplier.Code
ORDER BY dbo.Supplier.Date, dbo.Items.ID DESC



运行:Windows Server 2003上的SQL Server 2005

附加关键字:如何使用升序或降序更新SQL列 - 数值/如何在SQL更新语句中设置顺序/如何在sql视图中保存顺序/增量sql update / auto autoincrement sql update / create sql field with ascending编号

答案 6 :(得分:1)

我遇到了类似的问题,并使用ROW_NUMBER()结合OVER关键字解决了这个问题。任务是根据原始CreatedDate在一个简单表中追溯填充新的TicketNo(整数)字段,并按ModuleId分组 - 以便每个模块组中的票号从1开始并按日期递增。该表已有TicketID主键(GUID)。

这是SQL:

UPDATE Tickets SET TicketNo=T2.RowNo
FROM Tickets
INNER JOIN 
  (select TicketID, TicketNo, 
     ROW_NUMBER() OVER (PARTITION BY ModuleId ORDER BY DateCreated) AS RowNo from Tickets) 
  AS T2 ON T2.TicketID = Tickets.TicketID

做了一个款待!

答案 7 :(得分:0)

SET @pos := 0;
UPDATE TABLE SET position = ( SELECT @pos := @pos + 1 ) ORDER BY updated_at DESC;

答案 8 :(得分:0)

IF OBJECT_ID('tempdb..#TAB') IS NOT NULL
BEGIN
    DROP TABLE #TAB
END

CREATE TABLE #TAB(CH1 INT,CH2 INT,CH3 INT)

DECLARE @CH2 INT = NULL , @CH3 INT=NULL,@SPID INT=NULL,@SQL NVARCHAR(4000)='', @ParmDefinition NVARCHAR(50)= '',
@RET_MESSAGE AS VARCHAR(8000)='',@RET_ERROR INT=0


SET @ParmDefinition='@SPID INT,@CH2 INT OUTPUT,@CH3 INT OUTPUT'

SET @SQL='UPDATE T
            SET CH1=@SPID,@CH2= T.CH2,@CH3= T.CH3
            FROM #TAB T WITH(ROWLOCK)
            INNER JOIN (
                        SELECT TOP(1)  CH1,CH2,CH3
                        FROM
                        #TAB WITH(NOLOCK)
                        WHERE CH1 IS NULL
                        ORDER BY CH2 DESC) V ON T.CH2= V.CH2 AND T.CH3= V.CH3' 

INSERT INTO #TAB
(CH2 ,CH3 )
SELECT 1,2 UNION ALL
SELECT 2,3 UNION ALL
SELECT 3,4

BEGIN TRY
    WHILE EXISTS(SELECT TOP 1 1 FROM #TAB WHERE CH1 IS NULL)
    BEGIN

        EXECUTE @RET_ERROR = sp_executesql @SQL, @ParmDefinition,@SPID =@@SPID,  @CH2=@CH2 OUTPUT,@CH3=@CH3 OUTPUT;  

        SELECT * FROM #TAB
        SELECT @CH2,@CH3

    END

END TRY
BEGIN CATCH

    SET @RET_ERROR=ERROR_NUMBER()
    SET @RET_MESSAGE =  '@ERROR_NUMBER : ' + CAST(ERROR_NUMBER()  AS VARCHAR(255)) + '@ERROR_SEVERITY  :' + CAST( ERROR_SEVERITY()  AS VARCHAR(255)) 
    + '@ERROR_STATE :' + CAST(ERROR_STATE() AS VARCHAR(255)) + '@ERROR_LINE :' + CAST( ERROR_LINE() AS VARCHAR(255)) 
    +  '@ERROR_MESSAGE :' + ERROR_MESSAGE()  ;

    SELECT @RET_ERROR,@RET_MESSAGE;

END CATCH

答案 9 :(得分:-1)

我已经在MYSQL中测试了以下代码来更新最新记录。这就是我首先使用order by的原因。它将更新最新记录的状态列

 UPDATE DBTest.logTable
 SET status='Test' 
 ORDER BY ID DESC limit 1 ;