对结果集中的每一行执行动态更新语句

发布于 2025-01-01 03:33:00 字数 1714 浏览 2 评论 0原文

我正在尝试编写一个数据滚动脚本,该脚本将定位演示数据库中的所有日期时间列,并将它们向前滚动 x 天。由于我们的数据库架构尚未设置(仍在开发中),我试图尽可能保持动态。除了几列(我稍后将排除)之外,此语句标识了一个更新语句,它将向前滚动日期时间列:

SELECT 

    'UPDATE ' + [isc].[TABLE_NAME] + ' SET ' +
    [isc].[COLUMN_NAME] + 
    '= ' + [isc].[COLUMN_NAME] + '+ ' + 
    CAST(@DaysToRollForward AS NVARCHAR(5))  AS DySQL

FROM [INFORMATION_SCHEMA].COLUMNS AS isc
INNER JOIN [INFORMATION_SCHEMA].tables AS ist
    ON [ist].[TABLE_NAME] = [isc].[TABLE_NAME]
        WHERE [isc].[DATA_TYPE] = 'datetime'
            AND [ist].[TABLE_TYPE] = 'base table' 

我不反对使用游标,因为这只是一个演示服务器,并且永远不会真正看到太多的负载。我们这样做只是为了保持记录最新,以便我们始终在应用程序中看到数据。我已经尝试过下面的游标,它没有执行 UPDATE 语句。有什么想法吗?我的想法正确吗?我在这里看到了一些帮助帖子,但大多数都是在 BEGIN - END 块中执行存储过程。另外,如果有一个基于集合的方法,我会对此感兴趣,尽管如果有一个简单的修复我的光标的方法也很好。正如我提到的,这只是一个演示/质量保证服务器。

USE [sCRMDB1_demo]

GO

DECLARE @OrganizationId BIGINT
DECLARE @dySQL NVARCHAR(256)
DECLARE @DaysToRollForward INT


SET @DaysToRollForward = 7

DECLARE db_cursor_rollbackdates CURSOR FOR

SELECT 
    'UPDATE ' + [isc].[TABLE_NAME] + ' SET ' +
    [isc].[COLUMN_NAME] + 
    '= ' + [isc].[COLUMN_NAME] + '+ ' + 
    CAST(@DaysToRollForward AS NVARCHAR(5))  AS DySQL

FROM [INFORMATION_SCHEMA].COLUMNS AS isc
INNER JOIN [INFORMATION_SCHEMA].tables AS ist
    ON [ist].[TABLE_NAME] = [isc].[TABLE_NAME]
        WHERE [isc].[DATA_TYPE] = 'datetime'
            AND [ist].[TABLE_TYPE] = 'base table' 


OPEN db_cursor_rollbackdates
FETCH NEXT FROM db_cursor_rollbackdates INTO @dySQL

WHILE @@FETCH_STATUS = 0

BEGIN
    --PRINT CAST(@dySQL AS NVARCHAR(200))
    EXEC (@dySQL)
    FETCH NEXT FROM db_cursor_rollbackdates
END

CLOSE db_cursor_rollbackdates
DEALLOCATE db_cursor_rollbackdates

I am attempting to write a data roller script that will locate all datetime columns in a demo database and roll them forward by x amount of days. I'm trying to keep this as dynamic as possible due to the fact that our database schema is not set (still in development). With the exception of a few columns (which I will exclude later), this statement identifies an update statement that will roll the datetime column forward:

SELECT 

    'UPDATE ' + [isc].[TABLE_NAME] + ' SET ' +
    [isc].[COLUMN_NAME] + 
    '= ' + [isc].[COLUMN_NAME] + '+ ' + 
    CAST(@DaysToRollForward AS NVARCHAR(5))  AS DySQL

FROM [INFORMATION_SCHEMA].COLUMNS AS isc
INNER JOIN [INFORMATION_SCHEMA].tables AS ist
    ON [ist].[TABLE_NAME] = [isc].[TABLE_NAME]
        WHERE [isc].[DATA_TYPE] = 'datetime'
            AND [ist].[TABLE_TYPE] = 'base table' 

I am not against using a cursor since this is only a demo server, and will never really see much of a load. We are just doing this to keep our records current so we always have data visible in the application. I've tried the below cursor, and it is not executing the UPDATE statements . Any ideas? Do I have the right idea? I've seen a few help posts on here, but most are executing a stored procedure within the BEGIN - END block. Also, if there is a set based approach to this, I would be interested in that, although if there is an easy fix to my cursor that would be fine too. As I mentioned this is only a demo / qa server.

USE [sCRMDB1_demo]

GO

DECLARE @OrganizationId BIGINT
DECLARE @dySQL NVARCHAR(256)
DECLARE @DaysToRollForward INT


SET @DaysToRollForward = 7

DECLARE db_cursor_rollbackdates CURSOR FOR

SELECT 
    'UPDATE ' + [isc].[TABLE_NAME] + ' SET ' +
    [isc].[COLUMN_NAME] + 
    '= ' + [isc].[COLUMN_NAME] + '+ ' + 
    CAST(@DaysToRollForward AS NVARCHAR(5))  AS DySQL

FROM [INFORMATION_SCHEMA].COLUMNS AS isc
INNER JOIN [INFORMATION_SCHEMA].tables AS ist
    ON [ist].[TABLE_NAME] = [isc].[TABLE_NAME]
        WHERE [isc].[DATA_TYPE] = 'datetime'
            AND [ist].[TABLE_TYPE] = 'base table' 


OPEN db_cursor_rollbackdates
FETCH NEXT FROM db_cursor_rollbackdates INTO @dySQL

WHILE @@FETCH_STATUS = 0

BEGIN
    --PRINT CAST(@dySQL AS NVARCHAR(200))
    EXEC (@dySQL)
    FETCH NEXT FROM db_cursor_rollbackdates
END

CLOSE db_cursor_rollbackdates
DEALLOCATE db_cursor_rollbackdates

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七堇年 2025-01-08 03:33:00

你会踢自己的...

在循环中,

FETCH NEXT FROM db_cursor_rollbackdates

这本质上只是一个 select 语句,并且 @dySQL 保持不变,因此你的行 EXEC(@dySQL) 一遍又一遍地执行相同的更新,这就是为什么你不这样做查看数据库中更新的日期。您需要将其更改为:

FETCH NEXT FROM db_cursor_rollbackdates INTO @dySQL

这无法在基于集合的解决方案中完成,因为您正在更新多个表中的多个列。在替代解决方案方面,搜索“游标与临时表”并自行决定性能影响。我个人更喜欢临时表方法,但是如果我建议这是“正确”的方法,可能会被一些人处以私刑!另外,如果您有很多包含多个日期时间列和大量数据的表,那么您可以通过使用临时表和使用嵌套循环来稍微提高性能,即循环遍历至少包含一个日期时间列的所有表,然后在每个循环中循环通过所有日期时间列为每个表动态构建 SQL,以便每个表只执行一次更新,无论它们有多少个日期时间列。由于这是一个开发服务器,并且在生产服务器上不需要相同的过程,如果我是您,我就不会担心它的性能,只要它可以专注于其他开发领域即可!

最后请注意其他日期格式(Smalldatetime、Date、Datetime2),您的光标目前不会选择它们。

You'll kick yourself...

Within the loop you have

FETCH NEXT FROM db_cursor_rollbackdates

this is essentially just a select statement and leaves @dySQL unaltered, so your line EXEC(@dySQL) is doing the same update over and over again, this is why you are not seeing the days updated across the database. You need to change this to:

FETCH NEXT FROM db_cursor_rollbackdates INTO @dySQL

This can't be done in a set based solution, since you are updating multiple columns in multiple tables. In terms of alternative solutions, search for "Cursors vs Temp tables" and make your own mind up on performance impacts. I personally prefer the temp table approach, however would probably be lynched by some if I suggested this was the "correct" way to go! Also, if you have a lot of tables with multiple datetime columns and large amounts of data then you might increase performance slightly by using temp tables and using nested loops i.e. loop through all tables with at least one datetime column in, then within each loop loop through all the datetime columns building the sql dynamically for each table so that only one update is done per table, no matter how many datetime columns they have. Since this is a development server, and the same procedure won't be required on the production server I would not worry about performance of this if I were you, as long as it works concentrate on other areas of development!

Finally be aware of other date formats (Smalldatetime, Date, Datetime2), your cursor currently won't pick them up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文