2013-05-29 3 views
1

Я пытаюсь создать хранимую процедуру, содержащую оператор merge. Я хочу, чтобы оператор merge мог использовать переменную @TargetTable в качестве цели, но он просит меня использовать переменную таблицы. Это мой код:Как создать оператор MERGE с переменной в SQL Server

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 в исходной таблице была в моей последней хранимой процедуре работы, я связан с таблицей протоколирования для обработки дополнительной загрузки. Я также удалил оператор Source Delete, поскольку мой источник использовал мягкие удаления. Не стесняйтесь добавлять обратно.

Вот ссылка на сообщение в блоге и SP по AW ниже. 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

Смежные вопросы