8indie8
8indie8

Reputation: 71

Dynamic update issue

I have a table, let's call it "table_X" in that table I have multiple columns (46) and in the future there is a possibility that we will expand it to have more columns, since the source of a table is an old ERP system, we need to transform the dataset in some cases, one of the transformation is that when we replace the '' values with NULLs and here is where I have problem, I wrote a dynamic update, because the previously mentioned reason (in the future we will have more columns), but I got error message and right now I am stuck.

 DECLARE @SQL_columnnull NVARCHAR(max)
 DECLARE @db2 NVARCHAR(max)
 DECLARE @table2 NVARCHAR(max)
    
 SET @db2 = 'db'
 SET @table2 = 'table_X'

SELECT @SQL_columnnull_part_1 = STRING_AGG(CAST( N' UPDATE '+@db2+'.[dbo].'+@table2+' WITH (TABLOCK) SET ' AS NVARCHAR(MAX)) 
  +QUOTENAME(COLUMN_NAME,'['']')  + N' = NULL WHERE '
  +QUOTENAME(COLUMN_NAME,'['']') ,+ N' = '''';') 
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = @table2
 AND INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION <= 3 

for the two first column, the code is able to populate the command parts properly, but when it reaches the last column then the "='';" won't be populated

 UPDATE db.[dbo].table_X SET [Column_1] = NULL WHERE [Column_1] = ''; 
 UPDATE db.[dbo].table_X SET [Column_2] = NULL WHERE [Column_2] = ''; 
 UPDATE db.[dbo].table_X SET [Column_3] = NULL WHERE [Column_3]

Upvotes: 0

Views: 46

Answers (1)

S&#248;ren Kongstad
S&#248;ren Kongstad

Reputation: 1440

You are messing a bit about with your STRING_AGG

The syntax is

STRING_AGG ( expression, separator )

Your separator is

+ N' = '''';'

Since the separator is not applied after the last entry, you get the result you see!

I would also be wary of the cast, you are casting the start of the expression as nvarchar(max), however you are the concatenationg non varchar strings.

Finally - why are you doing separate updates for each column? this is very poor performance!

First, a fixed query that does what you want would be:

SELECT
    @SQL_columnnull = 
    STRING_AGG(
      CAST(
        ' UPDATE ' + @db2 + '.[dbo].' + @table2 + ' WITH (TABLOCK) SET ' 
          + QUOTENAME(COLUMN_NAME, '['']') + N' = NULL WHERE '
          + QUOTENAME(COLUMN_NAME, '['']') +N' = '''''
      AS NVARCHAR(MAX))
    ,';')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table2
AND INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION <= 3

I have included the full string within the cast, and the separator is now simply ";"

For performance I would however do this in stead:

SELECT
    @SQL_columnnull =
    N' UPDATE ' + @db2 + '.[dbo].' + @table2 + ' WITH (TABLOCK) SET ' +
    STRING_AGG(
      CAST( 
          QUOTENAME(COLUMN_NAME, '['']') + N'='+N'IIF('+ QUOTENAME(COLUMN_NAME, '['']') + N'= '''',NULL,'+ QUOTENAME(COLUMN_NAME, '['']')+') '
      AS NVARCHAR(MAX))
    ,',
    ')
    +' 
    WHERE '+
    STRING_AGG(
      CAST( 
           QUOTENAME(COLUMN_NAME, '['']') + N'= '''' '
      AS NVARCHAR(MAX))
    ,' OR ')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table2
AND INFORMATION_SCHEMA.COLUMNS.ORDINAL_POSITION <= 3

This does just one pass over your table, and updates the columns that have the wrong data. Finally I would check that all the columns are of a varchar or nvarchar data type, to exclude columns of othe datattypes which might give errors

This gives

UPDATE db.[dbo].table_X
SET [Column_1] = IIF([Column_1] = '', NULL, [Column_1])
   ,[Column_2] = IIF([Column_2] = '', NULL, [Column_2])
   ,[Column_3] = IIF([Column_3] = '', NULL, [Column_3])
WHERE [Column_1] = ''
OR [Column_2] = ''
OR [Column_3] = ''

Upvotes: 1

Related Questions