2012-04-17 6 views
1

EDIT:データベース名を簡単にするために変更されているSQL更新が

私は別のデータベースにいくつかの主要な生産のテーブルの静的コピーを更新するための場所にいくつかの動的SQLを取得しようとしている(sql2008r2 )。ここでの目標は、生産データベースがほぼ毎日更新されるため、特定の期間、(静的なデータベースからの)データの一貫した配布を可能にすることです。

私はCURSORを使用して、 '静的'データベースにコピーされるオブジェクトを含むテーブルをループします。

    prodの表は、その頻繁に変更されませんが、私はこのやや「未来の証明」をしたいのですが(可能ならば!)と(代わりに SELECT * FROM ...を使用しての)各オブジェクトに対して INFORMATION_SCHEMA.COLUMNSから列名を抽出します私は他の記事で読んだものから、
  • 1)、EXEC()は限定的なものと思われるので、私は、私はEXEC sp_executesqlを使用する必要があるだろうと信じているが、私はそれをすべてのまわりで私の頭を取得して少し問題を抱えています。追加の余分として

  • 2)、すべての可能で、私はまた、特定のテーブルの一部の列を除外したい場合(構造は「静的」データベースに多少異なります)

ここで私は何ですこれまでのところあります。 @colnamesがNULLを返すため、@sqlがNULLを返します。

解決策が見つかるかもしれない人に私を導くことができますか?
このコードに関する助言や助けをいただければ幸いです。

CREATE PROCEDURE sp_UpdateRefTables 
    @debug bit = 0 
AS 
declare @proddbname varchar(50), 
    @schemaname varchar(50), 
    @objname varchar(150), 
    @wherecond varchar(150), 
    @colnames varchar(max), 
    @sql  varchar(max), 
    @CRLF  varchar(2) 

set @wherecond = NULL; 
set @CRLF = CHAR(10) + CHAR(13); 

declare ObjectCursor cursor for 
select databasename,schemaname,objectname 
from Prod.dbo.ObjectsToUpdate 

OPEN ObjectCursor ; 

FETCH NEXT FROM ObjectCursor 
INTO @proddbname,@schemaname,@objname ; 

while @@FETCH_STATUS=0 
begin 

if @objname = 'TableXx' 
    set @wherecond = ' AND COLUMN_NAME != ''ExcludeCol1''' 
if @objname = 'TableYy' 
    set @wherecond = ' AND COLUMN_NAME != ''ExcludeCol2''' 

--extract column names for current object 
select @colnames = coalesce(@colnames + ',', '') + QUOTENAME(column_name) 
from Prod.INFORMATION_SCHEMA.COLUMNS 
where TABLE_NAME = + QUOTENAME(@objname,'') + isnull(@wherecond,'') 

if @debug=1 PRINT '@colnames= ' + isnull(@colnames,'null') 

--replace all data for @objname 
[email protected] is used as schema name in Static database 
SELECT @sql = 'TRUNCATE TABLE ' + @proddbname + '.' + @objname + '; ' + @CRLF 
SELECT @sql = @sql + 'INSERT INTO ' + @proddbname + '.' + @objname + ' ' + @CRLF 
SELECT @sql = @sql + 'SELECT ' + @colnames + ' FROM ' + @proddbname + '.' + @schemaname + '.' + @objname + '; ' 

if @debug=1 PRINT '@sql= ' + isnull(@sql,'null') 

EXEC sp_executesql @sql 

FETCH NEXT FROM ObjectCursor 
INTO @proddbname,@schemaname,@objname ; 

end 
CLOSE ObjectCursor ; 
DEALLOCATE ObjectCursor ; 

P.S.私はSQLインジェクションについて読んだことがありますが、これは内部の管理タスクなので、私はここで安全だと推測しています!これに関するアドバイスもありがとうございます。

多くのことに感謝します。

答えて

1

クエリにSQLと動的SQLが混在しています(information_schema)。 SQL Serverは[column_name]ではなくcolumn_nameをメタデータに格納するため、QUOTENAMEはwhere句では不要であり、実際には一致を防ぐことができます。最後に、これは方法we should be deriving metadata in SQL Serverであるため、sys.columnsに変更します。試してください:

SELECT @colnames += ',' + name 
    FROM Prod.sys.columns 
    WHERE OBJECT_NAME([object_id]) = @objname 
    AND name <> CASE WHEN @objname = 'TableXx' THEN 'ExcludeCol1' ELSE '' END 
    AND name <> CASE WHEN @objname = 'TableYy' THEN 'ExcludeCol2' ELSE '' END; 

SET @colnames = STUFF(@colnames, 1, 1, ''); 
+0

多くのおかげで、私はこれを試してみましょう。私はINFORMATION_SCHEMA.Columnsが一番良いと思いましたが、答えに応じてsys.columnsに変更します。またIFをCASE文に変更しなければならないことも知っていましたが、「STUFF」を認識しておらず、これを見ていきます! :) – MarkusBee

+0

STUFFは先頭の '、'を取り除いています。これは、クエリ内の 'COALESCE'連結のすべての処理よりもずっと簡単です。 –

+0

あなたの答えは魅力的でした。どうもありがとう。私は問題を複雑に過ぎていたと思う。 私はCOALESCEの個人的な好みがあります - 私はもう少しエレガントで、この例ではSTUFFステートメントの必要性を軽減しています。しかし私はSTUFFの他の用途を見ることができるので、これを念頭に置いておく。 :) – MarkusBee