没有游标的SQL Server循环

时间:2015-11-06 23:38:08

标签: sql sql-server tsql

我必须创建更新2000条记录的日期列的测试数据,其中10行与日期相同,在第11行将日期减1。

这是T-SQL:

DECLARE @CNT INT = 0;
DECLARE @DAYSUBTRACT INT = 0;
DECLARE @ACCOUNT_ID INT;

DECLARE Update_Cursor CURSOR FOR
SELECT TOP 2000 ACCOUNT_ID 
FROM ACCOUNTS;

OPEN Update_Cursor;
FETCH NEXT FROM Update_Cursor INTO @ACCOUNT_ID;
WHILE @@FETCH_STATUS = 0
   BEGIN
      UPDATE ACCOUNTS
      SET DATE_OPENED = DATEADD(day,@DAYSUBTRACT,SYSDATETIME())
      WHERE ACCOUNT_ID = @ACCOUNT_ID

      SET @CNT = @CNT + 1;

      IF (@CNT%10 = 0) SET @DAYSUBTRACT = @DAYSUBTRACT - 1;

      FETCH NEXT FROM Update_Cursor INTO @ACCOUNT_ID;
   END;
CLOSE Update_Cursor;
DEALLOCATE Update_Cursor;
GO

如果不在T-SQL中使用游标,是否可以实现此目的?

2 个答案:

答案 0 :(得分:4)

逻辑有点难以理解,但似乎你要为前10行减去1,然后在接下来的10行减2,依此类推。你可以不用循环来做到这一点:

with toupdate as (
      SELECT TOP 2000 ACCOUNT_ID,
             ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as seqnum
      FROM ACCOUNTS
     )
update toupdate
    set date_opened = dateadd(day, - (1 + (seqnum - 1) / 10), SYSDATETIME());

正如评论中所述:结果不确定,因为TOP的使用没有ORDER BY

答案 1 :(得分:1)

戈登的做法当然更胜一筹;尽管如此,仍然可以将您的方法转换为不需要游标的方法。这是否是一种更好的方式取决于你:

DECLARE @CNT INT = 0;
DECLARE @DAYSUBTRACT INT = 0;
DECLARE @ACCOUNT_ID INT;

CREATE TABLE ##ACCOUNTS (ACCOUNT_ID INT NOT NULL);
INSERT INTO ##ACCOUNTS (ACCOUNT_ID)
SELECT TOP 2000 ACCOUNT_ID 
FROM ACCOUNTS;

SET @ACCOUNT_ID = (SELECT MIN(ACCOUNT_ID) FROM ##ACCOUNTS);
WHILE @ACCOUNT_ID IS NOT NULL
BEGIN
    UPDATE ACCOUNTS
    SET DATE_OPENED = DATEADD(day, @DAYSUBTRACT, SYSDATETIME())
    WHERE ACCOUNT_ID = @ACCOUNT_ID;

    SET @CNT = @CNT + 1;
    IF @CNT % 10 = 0 SET @DAYSUBTRACT = @DAYSUBTRACT - 1;

    DELETE FROM ##ACCOUNTS WHERE ACCOUNT_ID = @ACCOUNT_ID;
    SET @ACCOUNT_ID = (SELECT MIN(ACCOUNT_ID) FROM ##ACCOUNTS);
END