SQL Server - script to update database columns from varchar to nvarchar if not already nvarchar

前端 未结 5 1745
南笙
南笙 2020-12-16 19:02

I am in a situation where I must update an existing database structure from varchar to nvarchar using a script. Since this script is run everytime a configuration applicati

相关标签:
5条回答
  • 2020-12-16 19:23

    The issue with Josef's answer is that it would change NOT NULL fields to NULL after executing the queries. The following manipulation fixes it:

    SELECT cmd = 'alter table [' + c.table_schema + '].[' + c.table_name 
     + '] alter column [' + c.column_name + '] nvarchar('
     +CASE WHEN CHARACTER_MAXIMUM_LENGTH<=4000
           THEN CAST(CHARACTER_MAXIMUM_LENGTH as varchar(10)) ELSE 'max' END+')' 
     + CASE WHEN IS_NULLABLE='NO' THEN ' NOT NULL' ELSE '' END,*
    FROM information_schema.columns c
    WHERE c.data_type='varchar' 
    ORDER BY CHARACTER_MAXIMUM_LENGTH desc
    

    Credits to Igor's answer

    0 讨论(0)
  • 2020-12-16 19:26

    Fixed the space issue and added schema

    SELECT 'ALTER TABLE [' + isnull(schema_name(syo.object_id), sysc.name) + '].[' +  syo.name 
        + '] ALTER COLUMN ' + syc.name + ' NVARCHAR(' + case syc.max_length when -1 then 'MAX' 
            ELSE convert(nvarchar(10),syc.max_length) end + ');'
       FROM sys.objects syo
       JOIN sys.columns syc ON
         syc.object_id= syo.object_id
       JOIN sys.types syt ON
         syt.system_type_id = syc.system_type_id
        JOIN sys.schemas sysc ON
        syo.schema_id=sysc.schema_id
       WHERE 
         syt.name = 'varchar' 
        and syo.type='U'
    
    0 讨论(0)
  • 2020-12-16 19:47

    Further updated to fix MAX being replaced with -1.

    SELECT cmd = 'ALTER TABLE [' + c.table_schema + '].[' + c.table_name 
     + '] ALTER COLUMN [' + c.column_name + '] NVARCHAR('
     +CASE WHEN CHARACTER_MAXIMUM_LENGTH<=4000 THEN 
     CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN
     'MAX' ELSE CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) END ELSE 'MAX' END+')' 
     + CASE WHEN IS_NULLABLE='NO' THEN ' NOT NULL' ELSE '' END,*
    FROM information_schema.columns c
    WHERE c.data_type='VARCHAR' 
    ORDER BY CHARACTER_MAXIMUM_LENGTH DESC
    

    Credit to Nezam's Answer

    And another one to manage default values:

    SELECT cmd = 
    CASE WHEN name IS NOT NULL THEN
        'ALTER TABLE ' + c.table_name + ' DROP CONSTRAINT ' + d.name + '; ' +
        'ALTER TABLE [' + c.table_schema + '].[' + c.table_name + '] ALTER COLUMN [' + c.column_name + '] ' + 
        'NVARCHAR(' +
        CASE WHEN CHARACTER_MAXIMUM_LENGTH <= 4000 THEN 
            CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN
                'MAX' 
            ELSE 
                CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) 
            END 
         ELSE 
            'MAX' 
        END 
        + ')' +
        CASE WHEN IS_NULLABLE='NO' THEN ' NOT NULL' ELSE '' END + '; ' + 
        'ALTER TABLE '+ c.table_name + ' ADD CONSTRAINT ' + d.name +' DEFAULT '+ c.column_default + ' FOR ' + c.column_name + ';'
    ELSE
        'ALTER TABLE [' + c.table_schema + '].[' + c.table_name + '] ALTER COLUMN [' + c.column_name + '] ' +
        'NVARCHAR(' +
        CASE WHEN CHARACTER_MAXIMUM_LENGTH<=4000 THEN
            CASE WHEN CHARACTER_MAXIMUM_LENGTH = -1 THEN
                'MAX' 
            ELSE 
                CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) 
            END 
        ELSE 
            'MAX' 
        END
        + ')' +
        CASE WHEN IS_NULLABLE='NO' THEN ' NOT NULL' ELSE '' END 
    END,d.name, c.*
    FROM information_schema.columns c
    LEFT OUTER JOIN sys.default_constraints d ON d.parent_object_id = object_id(c.table_name)
    AND d.parent_column_id = columnproperty(object_id(c.table_name), c.column_name, 'ColumnId')
    WHERE c.data_type='VARCHAR' 
    ORDER BY CHARACTER_MAXIMUM_LENGTH DESC
    
    0 讨论(0)
  • 2020-12-16 19:48

    The following query should get you what you need:

    IF EXISTS 
      (SELECT *
       FROM sysobjects syo
       JOIN syscolumns syc ON
         syc.id = syo.id
       JOIN systypes syt ON
         syt.xtype = syc.xtype
       WHERE 
         syt.name = 'nvarchar' AND
         syo.name = 'MY TABLE NAME' AND
         syc.name = 'MY COLUMN NAME')
    BEGIN
       ALTER ...
    END
    
    0 讨论(0)
  • 2020-12-16 19:48

    You can run the following script which will give you a set of ALTER commands:

    SELECT 'ALTER TABLE ' + isnull(schema_name(syo.id), 'dbo') + '.' +  syo.name 
        + ' ALTER COLUMN ' + syc.name + ' NVARCHAR(' + case syc.length when -1 then 'MAX' 
            ELSE convert(nvarchar(10),syc.length) end + ');'
       FROM sysobjects syo
       JOIN syscolumns syc ON
         syc.id = syo.id
       JOIN systypes syt ON
         syt.xtype = syc.xtype
       WHERE 
         syt.name = 'varchar' 
        and syo.xtype='U'
    

    There are, however, a couple of quick caveats for you.

    1. This will only do tables. You'll want to scan all of your sprocs and functions to make sure they are changed to NVARCHAR as well.
    2. If you have a VARCHAR > 4000 you will need to modify it to be NVARCHAR(MAX)

    But those should be easily doable with this template.

    If you want this to run automagically you can set it in a WHILE clause.

    0 讨论(0)
提交回复
热议问题