循环更新多个列?

时间:2012-07-26 20:07:41

标签: sql loops

我有一个select语句,我想将其转换为表中名称为Variable[N]的所有列的更新语句。

例如,我想做这些事情:

  1. 我希望能够将下面的SQL转换为更新语句。
  2. 我有n个列,其名称为variable[N]。以下示例仅更新列variable63,但我想在名称为variable1variableN的所有列上动态运行更新,而不知道我提前有多少variable[N]列。此外,在下面的示例中,我将更新的结果导入NewCol。我实际上想要在可能的情况下使用结果更新相应的变量列,variable63在我的示例中。
  3. 我希望有一个包装器循环遍历variable1列到variableN,并对所有这些列执行相同的更新操作:

    SELECT  
         projectid
        ,documentid
        ,revisionno
        ,configurationid
        ,variable63
        ,ISNULL(Variable63, 
                (SELECT TOP 1 
                 variable63 
                 FROM table1 
                 WHERE 
                     documentid = t.documentid 
                 and projectid=t.projectid
                 and configurationid=t.configurationid 
                 and cast(revisionno as int) < cast(t.revisionno as int) 
                 AND Variable63 is NOT NULL 
                 ORDER BY 
                  projectid desc
                 ,documentid desc
                 ,revisionno desc
                 ,configurationid desc
                 )) as NewCol
    FROM    table1 t;
    

2 个答案:

答案 0 :(得分:0)

没有通用的方法来循环SQL中的变量,你应该知道你想要修改的内容。在某些数据库中,可以查询系统表以动态构建更新语句(我知道如何在InterBase中执行此操作并且它是狡猾的Firebird),但您还没有告诉我们您正在使用哪个数据库引擎。 / p>

下面是一种可以更新多个null字段的方法,COALESCE和CASE是做同样事情的两种方式,就像使用LEFT JOIN或NOT EXISTS一样。使用您和您的数据库引擎最适合的那些。请注意所有记录都将被更新,因此如果您的数据库包含数百万条记录,每条记录都很大并且您希望此查询执行很多次,这不是一个好的解决方案。

UPDATE table1 t
SET t.VARIABLE63 = 
  COALESCE(t.VARIABLE63, 
           (SELECT VARIABLE63
            FROM table1 t0
            LEFT JOIN table1 tNot 
                   ON tNot.documentid = t.documentid
                  AND tNot.projectid=t.projectid        
                  AND tNot.configurationid=t.configurationid
                  AND cast(tNot.revisionno as int) > cast(t0.revisionno as int)
                  AND cast(tNot.revisionno as int) < cast(t.revisionno as int)
                  AND tNot.Variable63 is NOT NULL
            WHERE t0.documentid = t.documentid
              AND t0.projectid=t.projectid        
              AND t0.configurationid=t.configurationid
              AND cast(t0.revisionno as int) < cast(t.revisionno as int)
              AND t0.Variable63 is NOT NULL
              AND tNot.Variable63 is NULL)),
    t.VARIABLE64 = CASE WHEN t.VARIABLE64 IS NOT NULL then t.VARIABLE64
                        ELSE (SELECT VARIABLE64
                              FROM table1 t0
                              WHERE t0.documentid = t.documentid
                                AND t0.projectid=t.projectid        
                                AND t0.configurationid=t.configurationid
                                AND cast(t0.revisionno as int) < cast(t.revisionno as int)
                                AND t0.Variable64 is NOT NULL
                                AND NOT EXISTS(SELECT 1 
                                               FROM table1 tNot 
                                               WHERE tNot.documentid = t.documentid
                                                 AND tNot.projectid=t.projectid        
                                                 AND tNot.configurationid=t.configurationid
                                                 AND cast(tNot.revisionno as int) > cast(t0.revisionno as int)
                                                 AND cast(tNot.revisionno as int) < cast(t.revisionno as int)
                                                 AND tNot.Variable64 is NOT NULL)) END

答案 1 :(得分:0)

好吧,我想我明白了。循环遍历列并在每列上运行更新命令的函数。

DECLARE @sql NVARCHAR(1000),
@cn NVARCHAR(1000)--,
--@r NVARCHAR(1000),
--@start INT

DECLARE col_names CURSOR FOR
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'PIVOT_TABLE'
ORDER BY ordinal_position

--SET @start = 0
DECLARE @op VARCHAR(max)
SET @op=''

OPEN col_names FETCH next FROM col_names INTO @cn

WHILE @@FETCH_STATUS = 0
BEGIN
    --print @cn
    IF UPPER(@cn)<> 'DOCUMENTID' and UPPER(@cn)<> 'CONFIGURATIONID' and UPPER(@cn)<> 'PROJECTID' and UPPER(@cn)<> 'REVISIONNO'
    BEGIN
        SET @sql = 'UPdate pt
        set pt.' + @cn + ' = ((SELECT TOP 1 t.' + @cn + ' FROM pivot_table t WHERE t.documentid = pt.documentid and t.projectid=pt.projectid
        and t.configurationid=pt.configurationid and cast(t.revisionno as int) < cast(pt.revisionno as int) AND t.' + @cn + ' is NOT NULL 
        ORDER BY revisionno desc)) from PIVOT_TABLE pt where pt.' + @cn + ' is NULL;'
        EXEC Sp_executesql
        @sql
        --print @cn
    END
    FETCH next FROM col_names INTO @cn
END

CLOSE col_names
DEALLOCATE col_names;