In SQL Server, how do I generate a CREATE TABLE statement for a given table?

前端 未结 16 2194
离开以前
离开以前 2020-11-22 11:34

I\'ve spent a good amount of time coming up with solution to this problem, so in the spirit of this post, I\'m posting it here, since I think it might be useful to others. <

相关标签:
16条回答
  • 2020-11-22 11:58

    -- or you could create a stored procedure ... first with Id creation

    USE [db]
    GO
    
    /****** Object:  StoredProcedure [dbo].[procUtils_InsertGeneratorWithId]    Script Date: 06/13/2009 22:18:11 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    
    create PROC [dbo].[procUtils_InsertGeneratorWithId]    
    (    
    @domain_user varchar(50),    
    @tableName varchar(100)    
    )     
    
    
    as    
    
    --Declare a cursor to retrieve column specific information for the specified table    
    DECLARE cursCol CURSOR FAST_FORWARD FOR     
    SELECT column_name,data_type FROM information_schema.columns WHERE table_name = @tableName    
    OPEN cursCol    
    DECLARE @string nvarchar(3000) --for storing the first half of INSERT statement    
    DECLARE @stringData nvarchar(3000) --for storing the data (VALUES) related statement    
    DECLARE @dataType nvarchar(1000) --data types returned for respective columns    
    DECLARE @IDENTITY_STRING nvarchar ( 100 )    
    SET @IDENTITY_STRING = ' '     
    select  @IDENTITY_STRING    
    SET @string='INSERT '+@tableName+'('    
    SET @stringData=''    
    
    DECLARE @colName nvarchar(50)    
    
    FETCH NEXT FROM cursCol INTO @colName,@dataType    
    
    IF @@fetch_status<>0    
     begin    
     print 'Table '+@tableName+' not found, processing skipped.'    
     close curscol    
     deallocate curscol    
     return    
    END    
    
    WHILE @@FETCH_STATUS=0    
    BEGIN    
    IF @dataType in ('varchar','char','nchar','nvarchar')    
    BEGIN    
     --SET @stringData=@stringData+'''''''''+isnull('+@colName+','''')+'''''',''+'    
     SET @stringData=@stringData+''''+'''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'    
    END    
    ELSE    
    if @dataType in ('text','ntext') --if the datatype is text or something else     
    BEGIN    
     SET @stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(2000)),'''')+'''''',''+'    
    END    
    ELSE    
    IF @dataType = 'money' --because money doesn't get converted from varchar implicitly    
    BEGIN    
     SET @stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'    
    END    
    ELSE     
    IF @dataType='datetime'    
    BEGIN    
     --SET @stringData=@stringData+'''convert(datetime,''''''+isnull(cast('+@colName+' as varchar(200)),''0'')+''''''),''+'    
     --SELECT 'INSERT Authorizations(StatusDate) VALUES('+'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations    
     --SET @stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'    
     SET @stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'    
      --                             'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations    
    END    
    ELSE     
    IF @dataType='image'     
    BEGIN    
     SET @stringData=@stringData+'''''''''+isnull(cast(convert(varbinary,'+@colName+') as varchar(6)),''0'')+'''''',''+'    
    END    
    ELSE --presuming the data type is int,bit,numeric,decimal     
    BEGIN    
     --SET @stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(200)),''0'')+'''''',''+'    
     --SET @stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'    
     SET @stringData=@stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'    
    END    
    
    SET @string=@string+@colName+','    
    
    FETCH NEXT FROM cursCol INTO @colName,@dataType    
    END    
    DECLARE @Query nvarchar(4000)    
    
    SET @query ='SELECT '''+substring(@string,0,len(@string)) + ') VALUES(''+ ' + substring(@stringData,0,len(@stringData)-2)+'''+'')'' FROM '+@tableName    
    exec sp_executesql @query    
    --select @query    
    
    CLOSE cursCol    
    DEALLOCATE cursCol    
    
    
      /*
    USAGE
    
    */
    
    GO
    

    -- and second without iD INSERTION

    USE [db]
    GO
    
    /****** Object:  StoredProcedure [dbo].[procUtils_InsertGenerator]    Script Date: 06/13/2009 22:20:52 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROC [dbo].[procUtils_InsertGenerator]        
    (        
    @domain_user varchar(50),        
    @tableName varchar(100)        
    )         
    
    
    as        
    
    --Declare a cursor to retrieve column specific information for the specified table        
    DECLARE cursCol CURSOR FAST_FORWARD FOR         
    
    
    -- SELECT column_name,data_type FROM information_schema.columns WHERE table_name = @tableName        
    /* NEW     
    SELECT c.name , sc.data_type  FROM sys.extended_properties AS ep                   
    INNER JOIN sys.tables AS t ON ep.major_id = t.object_id                   
    INNER JOIN sys.columns AS c ON ep.major_id = c.object_id AND ep.minor_id                   
    = c.column_id                   
    INNER JOIN INFORMATION_SCHEMA.COLUMNS sc ON t.name = sc.table_name and                   
    c.name = sc.column_name                   
    WHERE t.name = @tableName and c.is_identity=0      
      */      
    
    select object_name(c.object_id) "TABLE_NAME", c.name "COLUMN_NAME", s.name "DATA_TYPE"      
      from sys.columns c          
      join sys.systypes s on (s.xtype = c.system_type_id)          
      where object_name(c.object_id) in (select name from sys.tables where name not like 'sysdiagrams')          
       AND object_name(c.object_id) in (select name from sys.tables where [name]=@tableName  ) and c.is_identity=0 and s.name not like 'sysname'  
    
    
    
    
    OPEN cursCol        
    DECLARE @string nvarchar(3000) --for storing the first half of INSERT statement        
    DECLARE @stringData nvarchar(3000) --for storing the data (VALUES) related statement        
    DECLARE @dataType nvarchar(1000) --data types returned for respective columns        
    DECLARE @IDENTITY_STRING nvarchar ( 100 )        
    SET @IDENTITY_STRING = ' '         
    select  @IDENTITY_STRING        
    SET @string='INSERT '+@tableName+'('        
    SET @stringData=''        
    
    DECLARE @colName nvarchar(50)        
    
    FETCH NEXT FROM cursCol INTO @tableName , @colName,@dataType        
    
    IF @@fetch_status<>0        
     begin        
     print 'Table '+@tableName+' not found, processing skipped.'        
     close curscol        
     deallocate curscol        
     return        
    END        
    
    WHILE @@FETCH_STATUS=0        
    BEGIN        
    IF @dataType in ('varchar','char','nchar','nvarchar')        
    BEGIN        
     --SET @stringData=@stringData+'''''''''+isnull('+@colName+','''')+'''''',''+'        
     SET @stringData=@stringData+''''+'''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'        
    END        
    ELSE        
    if @dataType in ('text','ntext') --if the datatype is text or something else         
    BEGIN        
     SET @stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(2000)),'''')+'''''',''+'        
    END        
    ELSE        
    IF @dataType = 'money' --because money doesn't get converted from varchar implicitly        
    BEGIN        
     SET @stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'        
    END        
    ELSE         
    IF @dataType='datetime'        
    BEGIN        
     --SET @stringData=@stringData+'''convert(datetime,''''''+isnull(cast('+@colName+' as varchar(200)),''0'')+''''''),''+'        
     --SELECT 'INSERT Authorizations(StatusDate) VALUES('+'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations        
     --SET @stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'        
     SET @stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'        
      --                             'convert(datetime,'+isnull(''''+convert(varchar(200),StatusDate,121)+'''','NULL')+',121),)' FROM Authorizations        
    END        
    ELSE         
    IF @dataType='image'         
    BEGIN        
     SET @stringData=@stringData+'''''''''+isnull(cast(convert(varbinary,'+@colName+') as varchar(6)),''0'')+'''''',''+'        
    END        
    ELSE --presuming the data type is int,bit,numeric,decimal         
    BEGIN        
     --SET @stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(200)),''0'')+'''''',''+'        
     --SET @stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'        
     SET @stringData=@stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'        
    END        
    
    SET @string=@string+@colName+','        
    
    FETCH NEXT FROM cursCol INTO @tableName , @colName,@dataType        
    END        
    DECLARE @Query nvarchar(4000)        
    
    SET @query ='SELECT '''+substring(@string,0,len(@string)) + ') VALUES(''+ ' + substring(@stringData,0,len(@stringData)-2)+'''+'')'' FROM '+@tableName        
    exec sp_executesql @query        
    --select @query       
    
    CLOSE cursCol        
    DEALLOCATE cursCol        
    
    
      /*      
    
    use poc     
    go    
    
    DECLARE @RC int      
    DECLARE @domain_user varchar(50)      
    DECLARE @tableName varchar(100)      
    
    -- TODO: Set parameter values here.      
    set @domain_user='yorgeorg'      
    set @tableName = 'tbGui_WizardTabButtonAreas'      
    
    EXECUTE @RC = [POC].[dbo].[procUtils_InsertGenerator]       
       @domain_user      
      ,@tableName      
    
    */
    GO
    
    0 讨论(0)
  • 2020-11-22 12:01

    Support for schemas:

    This is an updated version that amends the great answer from David, et al. Added is support for named schemas. It should be noted this may break if there's actually tables of the same name present within various schemas. Another improvement is the use of the official QuoteName() function.

    SELECT 
        t.TABLE_CATALOG,
        t.TABLE_SCHEMA,
        t.TABLE_NAME,
        'create table '+QuoteName(t.TABLE_SCHEMA)+'.' + QuoteName(so.name) + ' (' + LEFT(o.List, Len(o.List)-1) + ');  ' 
            + CASE WHEN tc.Constraint_Name IS NULL THEN '' 
              ELSE 
                'ALTER TABLE ' + QuoteName(t.TABLE_SCHEMA)+'.' + QuoteName(so.name) 
                + ' ADD CONSTRAINT ' + tc.Constraint_Name  + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ');  ' 
              END as 'SQL_CREATE_TABLE'
    FROM sysobjects so
    
    CROSS APPLY (
        SELECT 
              '  ['+column_name+'] ' 
              +  data_type 
              + case data_type
                    when 'sql_variant' then ''
                    when 'text' then ''
                    when 'ntext' then ''
                    when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
                  else 
                  coalesce(
                    '('+ case when character_maximum_length = -1 
                        then 'MAX' 
                        else cast(character_maximum_length as varchar) end 
                    + ')','') 
                end 
            + ' ' 
            + case when exists ( 
                SELECT id 
                FROM syscolumns
                WHERE 
                    object_name(id) = so.name
                    and name = column_name
                    and columnproperty(id,name,'IsIdentity') = 1 
              ) then
                'IDENTITY(' + 
                cast(ident_seed(so.name) as varchar) + ',' + 
                cast(ident_incr(so.name) as varchar) + ')'
              else ''
              end 
            + ' ' 
            + (case when IS_NULLABLE = 'No' then 'NOT ' else '' end) 
            + 'NULL ' 
            + case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT 
              ELSE '' 
              END 
            + ','  -- can't have a field name or we'll end up with XML
    
        FROM information_schema.columns 
        WHERE table_name = so.name
        ORDER BY ordinal_position
        FOR XML PATH('')
    ) o (list)
    
    LEFT JOIN information_schema.table_constraints tc on  
        tc.Table_name = so.Name
        AND tc.Constraint_Type  = 'PRIMARY KEY'
    
    LEFT JOIN information_schema.tables t on  
        t.Table_name = so.Name
    
    CROSS APPLY (
        SELECT QuoteName(Column_Name) + ', '
        FROM information_schema.key_column_usage kcu
        WHERE kcu.Constraint_Name = tc.Constraint_Name
        ORDER BY ORDINAL_POSITION
        FOR XML PATH('')
    ) j (list)
    
    WHERE
        xtype = 'U'
        AND name NOT IN ('dtproperties')
        -- AND so.name = 'ASPStateTempSessions'
    ;
    

    ..

    For use in Management Studio:

    One detractor to the sql code above is if you test it using SSMS, long statements aren't easy to read. So, as per this helpful post, here's another version that's somewhat modified to be easier on the eyes after clicking the link of a cell in the grid. The results are more readily identifiable as nicely formatted CREATE TABLE statements for each table in the db.

    -- settings
    DECLARE @CRLF NCHAR(2)
    SET @CRLF = Nchar(13) + NChar(10)
    DECLARE @PLACEHOLDER NCHAR(3)
    SET @PLACEHOLDER = '{:}'
    
    -- the main query
    SELECT 
        t.TABLE_CATALOG,
        t.TABLE_SCHEMA,
        t.TABLE_NAME,
        CAST(
            REPLACE(
                'create table ' + QuoteName(t.TABLE_SCHEMA) + '.' + QuoteName(so.name) + ' (' + @CRLF 
                + LEFT(o.List, Len(o.List) - (LEN(@PLACEHOLDER)+2)) + @CRLF + ');' + @CRLF
                + CASE WHEN tc.Constraint_Name IS NULL THEN '' 
                  ELSE
                    'ALTER TABLE ' + QuoteName(t.TABLE_SCHEMA) + '.' + QuoteName(so.Name) 
                    + ' ADD CONSTRAINT ' + tc.Constraint_Name  + ' PRIMARY KEY (' + LEFT(j.List, Len(j.List) - 1) + ');' + @CRLF
                  END,
                @PLACEHOLDER,
                @CRLF
            )
        AS XML) as 'SQL_CREATE_TABLE'
    FROM sysobjects so
    
    CROSS APPLY (
        SELECT 
              '   '
              + '['+column_name+'] ' 
              +  data_type 
              + case data_type
                    when 'sql_variant' then ''
                    when 'text' then ''
                    when 'ntext' then ''
                    when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
                  else 
                  coalesce(
                    '('+ case when character_maximum_length = -1 
                        then 'MAX' 
                        else cast(character_maximum_length as varchar) end 
                    + ')','') 
                end 
            + ' ' 
            + case when exists ( 
                SELECT id 
                FROM syscolumns
                WHERE 
                    object_name(id) = so.name
                    and name = column_name
                    and columnproperty(id,name,'IsIdentity') = 1 
              ) then
                'IDENTITY(' + 
                cast(ident_seed(so.name) as varchar) + ',' + 
                cast(ident_incr(so.name) as varchar) + ')'
              else ''
              end 
            + ' ' 
            + (case when IS_NULLABLE = 'No' then 'NOT ' else '' end) 
            + 'NULL ' 
            + case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT 
              ELSE '' 
              END 
            + ', ' 
            + @PLACEHOLDER  -- note, can't have a field name or we'll end up with XML
    
        FROM information_schema.columns where table_name = so.name
        ORDER BY ordinal_position
        FOR XML PATH('')
    ) o (list)
    
    LEFT JOIN information_schema.table_constraints tc on  
        tc.Table_name = so.Name
        AND tc.Constraint_Type  = 'PRIMARY KEY'
    
    LEFT JOIN information_schema.tables t on  
        t.Table_name = so.Name
    
    CROSS APPLY (
        SELECT QUOTENAME(Column_Name) + ', '
        FROM information_schema.key_column_usage kcu
        WHERE kcu.Constraint_Name = tc.Constraint_Name
        ORDER BY ORDINAL_POSITION
        FOR XML PATH('')
    ) j (list)
    
    WHERE
        xtype = 'U'
        AND name NOT IN ('dtproperties')
        -- AND so.name = 'ASPStateTempSessions'
    ;
    

    Not to belabor the point, but here's the functionally equivalent example outputs for comparison:

    -- 1 (scripting version)
    create table [dbo].[ASPStateTempApplications] (  [AppId] int  NOT NULL ,  [AppName] char(280)  NOT NULL );  ALTER TABLE [dbo].[ASPStateTempApplications] ADD CONSTRAINT PK__ASPState__8E2CF7F908EA5793 PRIMARY KEY  ([AppId]);  
    
    -- 2 (SSMS version)
    create table [dbo].[ASPStateTempSessions] (
       [SessionId] nvarchar(88)  NOT NULL , 
       [Created] datetime  NOT NULL DEFAULT (getutcdate()), 
       [Expires] datetime  NOT NULL , 
       [LockDate] datetime  NOT NULL , 
       [LockDateLocal] datetime  NOT NULL , 
       [LockCookie] int  NOT NULL , 
       [Timeout] int  NOT NULL , 
       [Locked] bit  NOT NULL , 
       [SessionItemShort] varbinary(7000)  NULL , 
       [SessionItemLong] image(2147483647)  NULL , 
       [Flags] int  NOT NULL DEFAULT ((0))
    );
    ALTER TABLE [dbo].[ASPStateTempSessions] ADD CONSTRAINT PK__ASPState__C9F4929003317E3D PRIMARY KEY ([SessionId]);
    

    ..

    Detracting factors:

    It should be noted that I remain relatively unhappy with this due to the lack of support for indeces other than a primary key. It remains suitable for use as a mechanism for simple data export or replication.

    0 讨论(0)
  • 2020-11-22 12:01

    I realise that it's been a very long time but thought I'd add anyway. If you just want the table, and not the create table statement you could use

    select into x from db.schema.y where 1=0
    

    to copy the table to a new DB

    0 讨论(0)
  • 2020-11-22 12:05

    If the application you are generating the scripts from is a .NET application, you may want to look into using SMO (Sql Management Objects). Reference this SQL Team link on how to use SMO to script objects.

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