dnlnln / generate-sql-merge

Generate SQL MERGE statements with Table data
MIT License
337 stars 151 forks source link

Allow for column names of 'Source' #109

Closed swiggins closed 6 months ago

swiggins commented 6 months ago

When using merge on tables with a column name of 'source' produces invalid sql.

Msg 207, Level 16, State 1, Line 20
Invalid column name 'target'.

Repo steps:

Create and populate a test table

create table test_merge (
    id int not null identity(1,1) primary key,
    field1 varchar(50) null,
    source varchar(50) null,
    field3 varchar(50) null
)

insert into test_merge (field1,[source],field3) values 
('a','b','c'),('d','e','f')

Generate the merge sql

DECLARE @sql NVARCHAR(MAX);
exec sp_generate_merge 'test_merge', @schema='dbo', @output = @sql output,@batch_separator=NULL, @include_use_db =0 , @results_to_text = null,  @disable_constraints = 1, @update_only_if_changed = 1
select @sql as col1

This outputs the following

-MERGE generated by [sp_generate_merge] proc tool. Acknowledgements: https://github.com/dnlnln/generate-sql-merge

SET NOCOUNT ON

SET IDENTITY_INSERT [dbo].[test_merge] ON

DECLARE @mergeOutput903699759 TABLE ( [DMLAction] VARCHAR(6) );
MERGE INTO [dbo].[test_merge] WITH (SERIALIZABLE) AS [Target]
USING (VALUES
  (1,'a','b','c')
 ,(2,'d','e','f')
) AS [Source] ([id],[field1],[source],[field3])
ON ([Target].[id] = [Source].[id])
WHEN MATCHED AND EXISTS (SELECT [Source].[field1], [Source].[source], [Source].[field3]
                 EXCEPT  SELECT [Target].[field1], [Target].[target], [Target].[field3]) THEN
 UPDATE SET
  [Target].[field1] = [Source].[field1], 
  [Target].[source] = [Source].[source], 
  [Target].[field3] = [Source].[field3]
WHEN NOT MATCHED BY TARGET THEN
 INSERT([id],[field1],[source],[field3])
 VALUES([Source].[id],[Source].[field1],[Source].[source],[Source].[field3])
WHEN NOT MATCHED BY SOURCE THEN 
 DELETE
OUTPUT $action INTO @mergeOutput903699759;

DECLARE @mergeError903699759 INT = @@ERROR, @mergeCount903699759 INT = (SELECT COUNT(1) FROM @mergeOutput903699759), @mergeCountIns903699759 INT = (SELECT COUNT(1) FROM @mergeOutput903699759 WHERE [DMLAction] = 'INSERT'), @mergeCountUpd903699759 INT = (SELECT COUNT(1) FROM @mergeOutput903699759 WHERE [DMLAction] = 'UPDATE'), @mergeCountDel903699759 INT = (SELECT COUNT(1) FROM @mergeOutput903699759 WHERE [DMLAction] = 'DELETE');
IF @mergeError903699759 <> 0 PRINT 'ERROR OCCURRED IN MERGE FOR [dbo].[test_merge]' + CONCAT(' (SQL Server error code: ', @mergeError903699759) + ')';
PRINT CONCAT('[dbo].[test_merge] rows affected by MERGE: ', @mergeCount903699759) + CONCAT(' (Inserted: ', @mergeCountIns903699759) + CONCAT('; Updated: ', @mergeCountUpd903699759) + CONCAT('; Deleted: ', @mergeCountDel903699759) + ')';

SET IDENTITY_INSERT [dbo].[test_merge] OFF
SET NOCOUNT OFF

Note the line with the EXCEPT operator selects a field called "target" which doesn't exist.

I've adjusted the proc sp_generate_merge to only replace the table names in @Column_List_For_Check to [Target] rather than include the column names.

dnlnln commented 6 months ago

@swiggins Thanks for taking the time to provide the repro steps and other details, much appreciated