2013-05-29 81 views
1

我試圖創建一個包含merge語句的存儲過程。我希望merge語句能夠使用變量@TargetTable作爲目標,但它要求我提供一個表變量。這是我的代碼:如何在SQL Server中使用變量創建MERGE語句

CREATE PROCEDURE dbo.mergetable 
(
    @TargetTable nvarchar(255) 
) 
AS 

SET NOCOUNT ON 
BEGIN 
MERGE INTO @TargetTable AS t 
USING dbo.SOURCE_TABLE AS s  
     ON t.name = s.name  
    WHEN MATCHED AND (t.record != s.record) THEN 
     --Row exists and data is different 
     UPDATE SET t.record= s.record 
    WHEN NOT MATCHED BY TARGET THEN 
     --Row exists in source but not in target 
     INSERT (name, record) 
     VALUES (s.name, s.record) 
    WHEN NOT MATCHED BY SOURCE THEN 
     --Row exists in target but not in source 
     DELETE 
     OUTPUT $action as ACTION, 
    DELETED.name AS Targetname, 
DELETED.record AS Targetrecord, 
INSERTED.name AS Sourcename, 
INSERTED.record AS Sourcerecord, 

SELECT @@ROWCOUNT; 
END 

我一直在使用一個表變量通過傳遞@TargetTable作爲數據的一個嘗試,並認爲這是可能的使用@TargetTable從臨時表,但我不知道如何編寫代碼

DECLARE @temp TABLE(temp varchar(50)); 
    INSERT @temp VALUES(@TargetTable) 

我只看到例子說明目標表,但不作爲變量。

有沒有辦法做到這一點?

在此先感謝

+1

不能參數化表(或列)名稱在T-SQL語句中使用。如果您必須這樣做,那麼您必須使用*動態SQL *在您的存儲過程中以字符串的形式構建T-SQL語句,然後執行代表語句的字符串 –

回答

0

謝謝marc_s您的回覆。我試圖使用動態SQL來解決這個問題,我發現這個網站有很好的教程,用於在存儲過程中編寫動態SQL。 [1] http://www.codeproject.com/Articles/20815/Building-Dynamic-SQL-In-a-Stored-Procedure

我嘗試了這兩種方法,並使用sp_executesql沒有爲我工作。使用sp_executesql給我一個錯誤,表變量@TargetTbl沒有聲明。

,這爲我工作:

CREATE PROCEDURE [dbo].[Update_Table] 
(
    @TargetTbl   NVARCHAR(100) 
) 
AS 
SET NOCOUNT ON 
DECLARE @SQLquery NVARCHAR(4000) 
SET @SQLquery = 'MERGE INTO ' + @TargetTbl + ' AS t '+ 
    'USING dbo.SOURCE_TABLE AS s ON t.name = s.name '+ 
    'WHEN MATCHED AND (t.record != s.record) '+ 
    'THEN UPDATE SET t.record = s.record '+ 
    'WHEN NOT MATCHED '+ 
    'THEN INSERT VALUES (s.name, s.record) '+ 
    'WHEN NOT MATCHED BY SOURCE THEN DELETE '+ 
    'OUTPUT $action as ACTION,'+ 
    'DELETED.name AS Targetname,'+ 
    'DELETED.record AS Targetrecord,'+ 
    'INSERTED.name AS Sourcename,'+ 
    'INSERTED.record AS Sourcerecord;' 

IF(@@ERROR = 0)  
    EXECUTE(@SQLquery) 
ELSE 
GoTo ErrorHandler 

Set NoCount OFF 
Return(0) 

ErrorHandler: 
    Return(@@ERROR) 

字符串都有要在NVARCHAR的代碼工作

+0

您說「每個字符串必須位於NVARCHAR '「爲它的工作,但所有的字符串文字不是。要將字符串文字指定爲'NVARCHAR',您需要在開頭引號前加上'N',例如。 'N'This是一個NVARCHAR文字''。或者,你的斷言是不正確的。 –

+0

你可能是對的。我不確定是否還需要添加前綴N,因爲我聲明SQLquery爲NVARCHAR。重要的是TargetTbl是NVARCHAR,而SQLquery也是NVARCHAR –

1

最近我有同樣的問題,並寫了一個存儲過程實現自動化MERGE語句創建併爲結果啓動sp_executesql。源表上CTE的原因是在我最後的工作存儲過程中,我鏈接到用於增量加載處理的日誌表。我還刪除了源刪除語句,因爲我的源使用了軟刪除。請隨時重新加入。

以下是指向以下AW博客帖子和SP的鏈接。 Using Dynamic T-SQL to Create Merge Statements

/* 
 
============================================================================== 
 
Author: \t \t  Tommy Swift 
 
Name:   spDynamicMerge 
 
Create date: 5/18/2015 
 
Description: \t Stored Procedure to Create MERGE Statements from Source Table 
 
       joining back to target tables on PK columns for CRUD statement 
 
       comparisons 
 
Parameters:  @schemaName - Default = 'dbo' 
 
\t \t \t \t @tableName to be Merged. 
 
\t \t \t \t Schema required if table schema name is other than 'dbo' 
 
Assumptions: - The parameter table exists on both the Source and Target 
 
        and PK's are the same on both DB tables. 
 
       - PK columns will be used to determine record existence. 
 
       - SP resides on the Target database where the filtered list 
 
        of columns per table occur. This ensures that only the 
 
        columns used in the Target are evaluated. 
 
============================================================================== 
 
*/ 
 

 
CREATE PROCEDURE [dbo].[spDynamicMerge] 
 
\t @schemaName VARCHAR(100) = 'dbo', 
 
\t @tableName VARCHAR(8000) 
 
AS 
 
BEGIN TRANSACTION \t 
 
\t SET NOCOUNT ON; 
 
\t BEGIN TRY 
 
    
 
    DECLARE @pkColumnsCompare VARCHAR(8000)    
 
      ,@nonPKColumnsTarget VARCHAR(8000) 
 
      ,@nonPKColumnsSource VARCHAR(8000) 
 
      ,@nonPKColumnsCompare VARCHAR(8000) 
 
      ,@columnListingSource VARCHAR(8000) 
 
      ,@columnListingTarget VARCHAR(8000) 
 
      ,@sqlCommand NVARCHAR(4000) 
 

 
    
 
    --Get list of PK columns for Insert determination 
 
    SELECT @pkColumnsCompare = COALESCE(@pkColumnsCompare + ' AND ', '') + 'Target.' + c.name + ' = ' + 'Source.' + c.name   
 
\t FROM sys.indexes i 
 
     INNER JOIN sys.index_columns ic 
 
      ON ic.object_id = i.object_id 
 
\t \t \t \t AND i.index_id = ic.index_id 
 
     INNER JOIN sys.columns c 
 
      ON ic.object_id = c.object_id 
 
       AND ic.column_id = c.column_id 
 
     INNER JOIN sys.tables t 
 
      ON t.object_id = c.object_id  
 
\t \t INNER JOIN sys.schemas s 
 
\t \t \t on s.schema_id = t.schema_id 
 
    WHERE i.is_primary_key = 1 
 
\t \t AND s.name + '.' + t.name = @schemaName + '.' + @tableName 
 

 
    
 
\t --Get List of non-PK columns for Updates 
 
    SELECT @nonPKColumnsTarget = COALESCE(@nonPKColumnsTarget + ', ', '') + 'Target.' + c.name 
 
     , @nonPKColumnsSource = COALESCE(@nonPKColumnsSource + ', ', '') + 'Source.' + c.name 
 
     , @nonPKColumnsCompare = COALESCE(@nonPKColumnsCompare + ', ', '') + 'Target.' + c.name + ' = ' + 'Source.' + c.name 
 
    FROM 
 
    (SELECT DISTINCT c.name 
 
    FROM sys.tables t 
 
     INNER JOIN sys.schemas s 
 
\t \t \t on s.schema_id = t.schema_id 
 
\t \t LEFT JOIN sys.columns c 
 
      ON t.object_id = c.object_id 
 
     LEFT JOIN sys.indexes i 
 
      ON i.object_id = c.object_id  
 
     LEFT JOIN sys.index_columns ic 
 
      ON ic.object_id = i.object_id 
 
       AND ic.column_id = c.column_id 
 
    WHERE ic.object_id IS NULL AND 
 
     s.name + '.' + t.name = @schemaName + '.' + @tableName   
 
    ) c 
 

 
    
 
    -- Create comma delimited column listing 
 
    SELECT @columnListingTarget = COALESCE(@columnListingTarget + ', ', '') + c.name 
 
     , @columnListingSource = COALESCE(@columnListingSource + ', ', '') + 'Source.'+ c.name  
 
    FROM 
 
    (SELECT DISTINCT c.name 
 
    FROM sys.tables t 
 
\t \t INNER JOIN sys.schemas s 
 
\t \t \t on s.schema_id = t.schema_id 
 
     INNER JOIN sys.columns c 
 
      ON t.object_id = c.object_id  
 
    WHERE s.name + '.' + t.name = @schemaName + '.' + @tableName   
 
    ) c 
 

 
    --select @pkColumnsCompare, @nonPKColumnsTarget, @nonPKColumnsSource, @nonPKColumnsCompare, @columnListingTarget, @columnListingSource 
 

 
    SELECT @sqlCommand = 
 
\t 'WITH temp AS ' + CHAR(13) + CHAR(10) + 
 
\t '(' + CHAR(13) + CHAR(10) + 
 
\t ' SELECT * FROM AdventureWorks2012.' + @schemaName + '.' + @tableName + ' WITH(NOLOCK) ' + CHAR(13) + CHAR(10) + \t \t 
 
\t ') ' + CHAR(13) + CHAR(10) + 
 
\t 'MERGE DataPatternsStage.' + @schemaName + '.' + @tableName + ' AS Target ' + CHAR(13) + CHAR(10) + 
 
    'USING temp AS Source ' + CHAR(13) + CHAR(10) + 
 
     'ON ' + @pkColumnsCompare + CHAR(13) + CHAR(10) + 
 
    ' WHEN MATCHED THEN ' + CHAR(13) + CHAR(10) + 
 
     'UPDATE SET ' + @nonPKColumnsCompare + CHAR(13) + CHAR(10) + 
 
    ' WHEN NOT MATCHED BY TARGET ' + CHAR(13) + CHAR(10) + 
 
    'THEN ' + CHAR(13) + CHAR(10) + 
 
     'INSERT (' + @columnListingTarget + ') ' + CHAR(13) + CHAR(10) + 
 
     'VALUES (' + @columnListingSource + '); ' 
 

 
    --select @sqlCommand 
 
    
 
    EXECUTE sp_executesql @sqlCommand 
 

 
\t END TRY 
 

 
\t BEGIN CATCH 
 
\t \t IF @@TRANCOUNT > 0 
 
     ROLLBACK TRANSACTION; 
 

 
\t \t DECLARE @ErrorMessage NVARCHAR(4000); 
 
\t \t DECLARE @ErrorSeverity INT; 
 
\t \t DECLARE @ErrorState INT; 
 

 
\t \t SELECT 
 
\t \t \t @ErrorMessage = ERROR_MESSAGE(), 
 
\t \t \t @ErrorSeverity = ERROR_SEVERITY(), 
 
\t \t \t @ErrorState = ERROR_STATE(); 
 

 
\t \t RAISERROR (@ErrorMessage, 
 
\t \t \t \t @ErrorSeverity, 
 
\t \t \t \t @ErrorState 
 
\t \t \t \t ); 
 

 
\t END CATCH; 
 

 
IF @@TRANCOUNT > 0 
 
    COMMIT TRANSACTION; 
 

 
GO

相關問題