使用动态 SQL 的 SQL While 循环

问题描述 投票:0回答:1

我正在尝试将 WHILE 循环与动态 SQL 结合使用。请参阅下面的代码。

我有一个表 [Users],其中列出了使用状态代码更新 [DB1] 中的字段所需的各种条件。代码运行,但是 [DB1] 仅根据 USERS 表中的最后一行更新了记录,这表明它没有循环遍历动态 SQL 变量。

有人可以建议如何迭代 [Users] 表吗?

请注意,我已使用 SQL Cursor 解决方案对此进行编码,但尝试使用 WHILE 循环。谢谢。

DECLARE @Field VARCHAR(50)
DECLARE @FieldType VARCHAR(10)
DECLARE @Operator CHAR(5)
DECLARE @Value VARCHAR(50)
DECLARE @Status VARCHAR(10)
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

DECLARE @Count INT = 1  
DECLARE @RowCount INT 
SET @RowCount = (SELECT COUNT(1) FROM [DB1])  

DECLARE @SQL VARCHAR(MAX)


WHILE @Count<=@RowCount

BEGIN

SELECT @Field = [Field]
,@FieldType= [FieldType]
,@Operator=[Operator]
,@Value=[Value]
,@Status=[Status]
,@StartDate=CONVERT(VARCHAR(11),[StartDate],106) 
,@EndDate=CONVERT(VARCHAR(11),[EndDate],106)

FROM [USERS] (NOLOCK)
ORDER BY [ConfigOrder] ASC


        SET @SQL= 'UPDATE [DB1]
        SET [Status] = ''' + @Status + '''' +
        'FROM [DB1] AS a (NOLOCK)
        INNER JOIN [DB2] AS b (NOLOCK) ON a.ID = b.ID
        WHERE b.[status] = ''UNK''
        AND ' + @Field + '' + @Operator + '' + @Value +
        'AND  a.[start_date] >= ''' + CONVERT(VARCHAR(11),@StartDate,106)  + '''' +
        'AND  a.[start_date] <= ''' + CONVERT(VARCHAR(11),@EndDate,106)  + '''' ;


EXEC (@SQL)

SET @Count=@Count+1

END
sql-server while-loop dynamic-sql
1个回答
0
投票

您在

DB1
上有隐式交叉连接,因为您正在执行
UPDATE DB1
而不是
UPDATE a

您不应该仅仅为了避免出现光标而使用

WHILE
,它并没有更快,甚至更慢。游标很慢,但是手动写通常更差。

还有

  • 您应该正确参数化动态 SQL,否则您将面临语法错误和注入问题。
  • 不要使用
    NOLOCK
    ,它会严重影响数据完整性。使用快照隔离来避免阻塞,或使用
    WITH (TABLOCK)
    来获得彻底的性能。
  • 动态 SQL 位于
    nvarchar(max)
    字段中。列和对象名称应为
    sysname
  • 我不知道你的意图,但在比较日期时间时通常最好使用半开区间,例如
    >= AND <
DECLARE @crsr CURSOR;
DECLARE @SQL NVARCHAR(MAX);
DECLARE @Value VARCHAR(50);
DECLARE @Status VARCHAR(10);
DECLARE @StartDate DATETIME;
DECLARE @EndDate DATETIME;

SET @crsr = CURSOR FAST_FORWARD FOR
SELECT
  '
UPDATE d1
SET Status = @Status
FROM DB1 AS d1
INNER JOIN DB2 AS d2 ON d1.ID = d2.ID
WHERE d2.status = ''UNK''
  AND ' + u.Field + ' ' + u.Operator + ' @Value
  AND d1.start_date >= @StartDate
  AND d1.start_date <= @EndDate;
',
  u.Status,
  u.Value,
  u.StartDate,
  u.EndDate
FROM [USERS] u
ORDER BY
  ConfigOrder ASC;

OPEN @crsr;
WHILE 1=1
BEGIN
    FETCH @crsr INTO @SQL, @Status, @Value, @StartDate, @EndDate;
    IF @@FETCH_STATUS <> 0 BREAK;

    PRINT @SQL;    -- your friend

    EXEC @SQL,
      N'@Value VARCHAR(50),
        @Status VARCHAR(10),
        @StartDate DATETIME,
        @EndDate DATETIME',
      @Value = @Value,
      @Status = @Status,
      @StartDate = @StartDate,
      @EndDate = @EndDate;
END;

-- no need to deallocate cursor in variable
© www.soinside.com 2019 - 2024. All rights reserved.