我正在尝试将 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
您在
DB1
上有隐式交叉连接,因为您正在执行 UPDATE DB1
而不是 UPDATE a
。
您不应该仅仅为了避免出现光标而使用
WHILE
,它并没有更快,甚至更慢。游标很慢,但是手动写通常更差。
还有
NOLOCK
,它会严重影响数据完整性。使用快照隔离来避免阻塞,或使用 WITH (TABLOCK)
来获得彻底的性能。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