【问题标题】:In SQL Server, how do I generate a CREATE TABLE statement for a given table?在 SQL Server 中,如何为给定表生成 CREATE TABLE 语句?
【发布时间】:2010-09-06 11:58:18
【问题描述】:

我花了很多时间想出解决这个问题的方法,所以本着this post 的精神,我把它贴在这里,因为我认为它可能对其他人有用。

如果有人有更好的脚本,或者有什么要补充的,请发布。

编辑:是的,伙计们,我知道如何在 Management Studio 中执行此操作 - 但我需要能够从另一个应用程序中执行此操作。

【问题讨论】:

    标签: sql-server scripting dynamic-sql


    【解决方案1】:

    基于 Hubbitus 答案的查询。

    • 包括架构名称
    • 修复具有多个字段的外键
    • 包括级联更新和删除
    • 包括一个有条件的 DROP TABLE
    SELECT 
      Schema_Name = SCHEMA_NAME(obj.uid)
    , Table_Name = name
    , Drop_Table = 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = ''' + SCHEMA_NAME(obj.uid) + '''  AND  TABLE_NAME = ''' + obj.name + '''))
    DROP TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] '
    , Create_Table ='
    CREATE TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] (' + LEFT(cols.list, LEN(cols.list) - 1 ) + ')' + ISNULL(' ' + refs.list, '')
        FROM sysobjects obj
        CROSS APPLY (
            SELECT 
                CHAR(10)
                + ' [' + column_name + '] '
                + data_type
                + CASE data_type
                    WHEN 'sql_variant' THEN ''
                    WHEN 'text' THEN ''
                    WHEN 'ntext' THEN ''
                    WHEN 'xml' 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 ( -- Identity skip
                                    select id from syscolumns
                                    where id = obj.id
                                    and name = column_name
                                    and columnproperty(id, name, 'IsIdentity') = 1 
                                    ) then
                            'IDENTITY(' + 
                                cast(ident_seed(obj.name) as varchar) + ',' + 
                                cast(ident_incr(obj.name) as varchar) + ')'
                else ''
                end + ' '
                + CASE WHEN IS_NULLABLE = 'No' THEN 'NOT ' ELSE '' END
                + 'NULL'
                + CASE WHEN IC.column_default IS NOT NULL THEN ' DEFAULT ' + IC.column_default ELSE '' END
                + ','
            FROM INFORMATION_SCHEMA.COLUMNS IC
            WHERE IC.table_name   = obj.name
              AND IC.TABLE_SCHEMA = SCHEMA_NAME(obj.uid)
            ORDER BY ordinal_position
            FOR XML PATH('')
        ) cols (list)
        CROSS APPLY(
            SELECT
                CHAR(10) + 'ALTER TABLE [' + SCHEMA_NAME(obj.uid) + '].[' + obj.name + '] ADD ' + LEFT(alt, LEN(alt)-1)
            FROM(
                SELECT
                    CHAR(10)
                    + ' CONSTRAINT ' + tc.constraint_name
                    + ' ' + tc.constraint_type + ' (' + LEFT(c.list, LEN(c.list)-1) + ')'
                    + COALESCE(CHAR(10) + r.list, ', ')
                FROM information_schema.table_constraints tc
                    CROSS APPLY(
                        SELECT   '[' + kcu.column_name + '], '
                        FROM     information_schema.key_column_usage kcu
                        WHERE    kcu.constraint_name = tc.constraint_name
                        ORDER BY kcu.ordinal_position
                        FOR XML PATH('')
                    ) c (list)
                    OUTER APPLY(
                        -- // http://stackoverflow.com/questions/3907879/sql-server-howto-get-foreign-key-reference-from-information-schema
                        SELECT LEFT(f.list, LEN(f.list)-1) + ')' + IIF(rc.DELETE_RULE = 'NO ACTION', '', ' ON DELETE ' + rc.DELETE_RULE) + IIF(rc.UPDATE_RULE = 'NO ACTION', '', ' ON UPDATE ' + rc.UPDATE_RULE) + ', '
                        FROM information_schema.referential_constraints rc
                        CROSS APPLY(
                            SELECT IIF(kcu.ordinal_position = 1, ' REFERENCES [' + kcu.table_schema + '].[' + kcu.table_name + '] (', '') 
                                    + '[' + kcu.column_name + '], '
                            FROM information_schema.key_column_usage kcu 
                            WHERE kcu.constraint_catalog = rc.unique_constraint_catalog AND kcu.constraint_schema = rc.unique_constraint_schema AND kcu.constraint_name = rc.unique_constraint_name
                            ORDER BY kcu.ordinal_position
                            FOR XML PATH('')
                        ) f (list)
                        WHERE rc.constraint_catalog = tc.constraint_catalog 
                          AND rc.constraint_schema  = tc.constraint_schema 
                          AND rc.constraint_name    = tc.constraint_name
                    ) r (list)
                WHERE tc.table_name = obj.name
                FOR XML PATH('')
            ) a (alt)
        ) refs (list)
        WHERE xtype = 'U'
    

    将 drop table(如果存在)与 create 结合使用,如下所示:

    SELECT Drop_Table + CHAR(10) + Create_Table FROM SysCreateTables
    

    【讨论】:

      【解决方案2】:

      我已修改上述版本以运行所有表并支持新的 SQL 2005 数据类型。它还保留主键名称。仅适用于 SQL 2005(使用交叉应用)。

      
      select  'create table [' + so.name + '] (' + o.list + ')' + CASE WHEN tc.Constraint_Name IS NULL THEN '' ELSE 'ALTER TABLE ' + so.Name + ' ADD CONSTRAINT ' + tc.Constraint_Name  + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ')' END
      from    sysobjects so
      cross apply
          (SELECT 
              '  ['+column_name+'] ' + 
              data_type + case data_type
                  when 'sql_variant' then ''
                  when 'text' then ''
                  when 'ntext' then ''
                  when 'xml' 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 UPPER(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 + ', ' 
      
           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'
      cross apply
          (select '[' + 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')
      
      

      更新:增加了对 XML 数据类型的处理

      更新 2: 修复了以下情况:1)有多个同名但架构不同的表,2)有多个具有相同名称的 PK 约束的表

      【讨论】:

      • 这太棒了!我一直在寻找这样的东西很长一段时间! (尝试将表结构编写到我们的版本控制中)
      • 感谢您发布此消息!我认为您应该使用 numeric_precision 列,而不是 numeric_precision_radix,并且除了小数数据类型之外,它对于 numeric 数据类型的工作方式应该相同。
      • 我认为你有一个错误 -- numeric_precision_radix 应该是 numeric_precision
      • 我注意到在运行它时,在列出列时输出的末尾有一个额外的逗号。我可以通过用STUFF(o.list,1,2,'') 将第1 行中的o.list 括起来并将逗号从第23 行的交叉应用的末尾移到第5 行的开头', ['+column_name+'] ' + 来删除多余的逗号
      • 通过@Imingle 更改,我还将LEFT(j.List, Len(j.List)-1) 更改为STUFF(j.List, 1,2,''),并将第33 行的逗号移到前面select ', [' + Column_Name + '] '
      【解决方案3】:

      这是我想出的脚本。它处理标识列、默认值和主键。它不处理外键、索引、触发器或任何其他聪明的东西。它适用于 SQLServer 2000、2005 和 2008。

      declare @schema varchar(100), @table varchar(100)
      set @schema = 'dbo' -- set schema name here
      set @table = 'MyTable' -- set table name here
      declare @sql table(s varchar(1000), id int identity)
      
      -- create statement
      insert into  @sql(s) values ('create table [' + @table + '] (')
      
      -- column list
      insert into @sql(s)
      select 
          '  ['+column_name+'] ' + 
          data_type + coalesce('('+cast(character_maximum_length as varchar)+')','') + ' ' +
          case when exists ( 
              select id from syscolumns
              where object_name(id)=@table
              and name=column_name
              and columnproperty(id,name,'IsIdentity') = 1 
          ) then
              'IDENTITY(' + 
              cast(ident_seed(@table) as varchar) + ',' + 
              cast(ident_incr(@table) as varchar) + ')'
          else ''
          end + ' ' +
          ( case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' + 
          coalesce('DEFAULT '+COLUMN_DEFAULT,'') + ','
      
       from INFORMATION_SCHEMA.COLUMNS where table_name = @table AND table_schema = @schema
       order by ordinal_position
      
      -- primary key
      declare @pkname varchar(100)
      select @pkname = constraint_name from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
      where table_name = @table and constraint_type='PRIMARY KEY'
      
      if ( @pkname is not null ) begin
          insert into @sql(s) values('  PRIMARY KEY (')
          insert into @sql(s)
              select '   ['+COLUMN_NAME+'],' from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
              where constraint_name = @pkname
              order by ordinal_position
          -- remove trailing comma
          update @sql set s=left(s,len(s)-1) where id=@@identity
          insert into @sql(s) values ('  )')
      end
      else begin
          -- remove trailing comma
          update @sql set s=left(s,len(s)-1) where id=@@identity
      end
      
      -- closing bracket
      insert into @sql(s) values( ')' )
      
      -- result!
      select s from @sql order by id
      

      【讨论】:

      • 由于动态 sql 的原因,许多系统将无法运行它。在您的本地盒子上可能不是问题,但只是想指出这一点。
      • 什么动态sql?此脚本生成 sql - 它不执行它。
      • 希望将其分解为多个步骤,以便可以通过一系列可以用 C++ 编写的查询来执行
      • 如果架构不是“dbo”,您将失去对架构的支持。此外,如果数据库具有相同的表名但架构不同,则会出现问题。我得到了我需要的东西,谢谢。
      • @TT。你确定吗? select cast(123456 as varchar) 为我返回 123456
      【解决方案4】:

      我意识到这已经很长时间了,但我还是想补充一下。如果您只想要表格,而不是您可以使用的 create table 语句

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

      将表复制到新数据库

      【讨论】:

      • 关于此方法的一个注意事项是,它不会复制约束或默认值等扩展信息,但它仍然是直接表复制的简单解决方案。
      【解决方案5】:

      我包含计算列的定义

          select 'CREATE TABLE [' + so.name + '] (' + o.list + ')' + CASE WHEN tc.Constraint_Name IS NULL THEN '' ELSE 'ALTER TABLE ' + so.Name + ' ADD CONSTRAINT ' + tc.Constraint_Name  + ' PRIMARY KEY ' + ' (' + LEFT(j.List, Len(j.List)-1) + ')' END, name
      from    sysobjects so
      cross apply
          (SELECT
      
      case when comps.definition is not null then '  ['+column_name+'] AS ' + comps.definition 
      else
              '  ['+column_name+'] ' + data_type + 
              case
              when data_type like '%text' or data_type in ('image', 'sql_variant' ,'xml')
                  then ''
              when data_type in ('float')
                  then '(' + cast(coalesce(numeric_precision, 18) as varchar(11)) + ')'
              when data_type in ('datetime2', 'datetimeoffset', 'time')
                  then '(' + cast(coalesce(datetime_precision, 7) as varchar(11)) + ')'
              when data_type in ('decimal', 'numeric')
                  then '(' + cast(coalesce(numeric_precision, 18) as varchar(11)) + ',' + cast(coalesce(numeric_scale, 0) as varchar(11)) + ')'
              when (data_type like '%binary' or data_type like '%char') and character_maximum_length = -1
                  then '(max)'
              when character_maximum_length is not null
                  then '(' + cast(character_maximum_length as varchar(11)) + ')'
              else ''
              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 information_schema.columns.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 
      end + ', ' 
      
           from information_schema.columns 
           left join sys.computed_columns comps 
           on OBJECT_ID(information_schema.columns.TABLE_NAME)=comps.object_id and information_schema.columns.COLUMN_NAME=comps.name
      
           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'
      cross apply
          (select '[' + 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')
      

      【讨论】:

        【解决方案6】:

        -- 或者你可以创建一个存储过程...首先创建 Id

        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
        

        --第二个没有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
        

        【讨论】:

          【解决方案7】:

          我将通过支持分区表来改进答案:

          使用以下脚本查找分区方案和分区键:

          declare @partition_scheme varchar(100) = (
          select distinct ps.Name AS PartitionScheme
          from sys.indexes i  
          join sys.partitions p ON i.object_id=p.object_id AND i.index_id=p.index_id  
          join sys.partition_schemes ps on ps.data_space_id = i.data_space_id  
          where i.object_id = object_id('your table name')
          )
          print @partition_scheme
          
          declare @partition_column varchar(100) = (
          select c.name 
          from  sys.tables          t
          join  sys.indexes         i 
                on(i.object_id = t.object_id 
            and i.index_id < 2)
          join  sys.index_columns  ic 
            on(ic.partition_ordinal > 0 
            and ic.index_id = i.index_id and ic.object_id = t.object_id)
          join  sys.columns         c 
            on(c.object_id = ic.object_id 
            and c.column_id = ic.column_id)
          where t.object_id  = object_id('your table name')
          )
          print @partition_column
          

          然后通过在正确的位置添加以下行来更改生成查询:

          + IIF(@partition_scheme is null, '', 'ON [' + @partition_scheme + ']([' + @partition_column + '])')
          

          【讨论】:

            【解决方案8】:

            在一个语句中支持外键的另一种变体:

             SELECT
                    obj.name
                    ,'CREATE TABLE [' + obj.name + '] (' + LEFT(cols.list, LEN(cols.list) - 1 ) + ')'
                    + ISNULL(' ' + refs.list, '')
                FROM sysobjects obj
                CROSS APPLY (
                    SELECT 
                        CHAR(10)
                        + ' [' + column_name + '] '
                        + data_type
                        + CASE data_type
                            WHEN 'sql_variant' THEN ''
                            WHEN 'text' THEN ''
                            WHEN 'ntext' THEN ''
                            WHEN 'xml' 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 ( -- Identity skip
                        select id from syscolumns
                        where object_name(id) = obj.name
                        and name = column_name
                        and columnproperty(id,name,'IsIdentity') = 1 
                        ) then
                        'IDENTITY(' + 
                        cast(ident_seed(obj.name) as varchar) + ',' + 
                        cast(ident_incr(obj.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
                        + ','
                    FROM
                        INFORMATION_SCHEMA.COLUMNS
                    WHERE table_name = obj.name
                    ORDER BY ordinal_position
                    FOR XML PATH('')
                ) cols (list)
                CROSS APPLY(
                    SELECT
                        CHAR(10) + 'ALTER TABLE ' + obj.name + '_noident_temp ADD ' + LEFT(alt, LEN(alt)-1)
                    FROM(
                        SELECT
                            CHAR(10)
                            + ' CONSTRAINT ' + tc.constraint_name
                            + ' ' + tc.constraint_type + ' (' + LEFT(c.list, LEN(c.list)-1) + ')'
                            + COALESCE(CHAR(10) + r.list, ', ')
                        FROM
                            information_schema.table_constraints tc
                            CROSS APPLY(
                                SELECT
                                    '[' + kcu.column_name + '], '
                                FROM
                                    information_schema.key_column_usage kcu
                                WHERE
                                    kcu.constraint_name = tc.constraint_name
                                ORDER BY
                                    kcu.ordinal_position
                                FOR XML PATH('')
                            ) c (list)
                            OUTER APPLY(
                                -- // http://stackoverflow.com/questions/3907879/sql-server-howto-get-foreign-key-reference-from-information-schema
                                SELECT
                                    '  REFERENCES [' + kcu1.constraint_schema + '].' + '[' + kcu2.table_name + ']' + '(' + kcu2.column_name + '), '
                                FROM information_schema.referential_constraints as rc
                                    JOIN information_schema.key_column_usage as kcu1 ON (kcu1.constraint_catalog = rc.constraint_catalog AND kcu1.constraint_schema = rc.constraint_schema AND kcu1.constraint_name = rc.constraint_name)
                                    JOIN information_schema.key_column_usage as kcu2 ON (kcu2.constraint_catalog = rc.unique_constraint_catalog AND kcu2.constraint_schema = rc.unique_constraint_schema AND kcu2.constraint_name = rc.unique_constraint_name AND kcu2.ordinal_position = KCU1.ordinal_position)
                                WHERE
                                    kcu1.constraint_catalog = tc.constraint_catalog AND kcu1.constraint_schema = tc.constraint_schema AND kcu1.constraint_name = tc.constraint_name
                            ) r (list)
                        WHERE tc.table_name = obj.name
                        FOR XML PATH('')
                    ) a (alt)
                ) refs (list)
                WHERE
                    xtype = 'U'
                AND name NOT IN ('dtproperties')
                AND obj.name = 'your_table_name'
            

            你可以试试 sqlfiddle:http://sqlfiddle.com/#!6/e3b66/3/0

            【讨论】:

            • 我喜欢这个单语句解决方案,它支持外键。 @tableName 的前 2 个实例可以替换为 so.name,这样可以更轻松地同时为多个表生成创建表脚本。
            • 此外,当没有单一约束(如主键)时,查询将为 NULL。要解决这个问题,' ' + j.list 应该是ISNULL(' ' + j.list, '')。我冒昧地为我的两个 cmets 中描述的用例调整了代码
            • @ChristiaanWesterbeek 的建议看起来很合理。但我不明白最后一个案例。 j.list 什么时候为空?可以举个例子吗?
            • 用你的小提琴中的表区试试。你会看到一个空值。最后一列还有一个不应存在的尾随逗号。不过还是喜欢你的回答:)
            • 啊,你说的桌子没有钥匙!谢谢,也修好了。最后一个逗号不是问题,因为它更正了 SQL,但它(以及更易读的子查询名称)也为 estetic 修复。
            【解决方案9】:

            我修改了接受的答案,现在它可以在某个模式中获取包含主键和外键的命令。

            declare @table varchar(100)
            declare @schema varchar(100)
            set @table = 'Persons' -- set table name here
            set @schema = 'OT' -- set SCHEMA name here
            declare @sql table(s varchar(1000), id int identity)
            
            -- create statement
            insert into  @sql(s) values ('create table ' + @table + ' (')
            
            -- column list
            insert into @sql(s)
            select 
                '  '+column_name+' ' + 
                data_type + coalesce('('+cast(character_maximum_length as varchar)+')','') + ' ' +
                case when exists ( 
                    select id from syscolumns
                    where object_name(id)=@table
                    and name=column_name
                    and columnproperty(id,name,'IsIdentity') = 1 
                ) then
                    'IDENTITY(' + 
                    cast(ident_seed(@table) as varchar) + ',' + 
                    cast(ident_incr(@table) as varchar) + ')'
                else ''
                end + ' ' +
                ( case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' + 
                coalesce('DEFAULT '+COLUMN_DEFAULT,'') + ','
            
             from information_schema.columns where table_name = @table and table_schema = @schema
             order by ordinal_position
            
            -- primary key
            declare @pkname varchar(100)
            select @pkname = constraint_name from information_schema.table_constraints
            where table_name = @table and constraint_type='PRIMARY KEY'
            
            if ( @pkname is not null ) begin
                insert into @sql(s) values('  PRIMARY KEY (')
                insert into @sql(s)
                    select '   '+COLUMN_NAME+',' from information_schema.key_column_usage
                    where constraint_name = @pkname
                    order by ordinal_position
                -- remove trailing comma
                update @sql set s=left(s,len(s)-1) where id=@@identity
                insert into @sql(s) values ('  )')
            end
            else begin
                -- remove trailing comma
                update @sql set s=left(s,len(s)-1) where id=@@identity
            end
            
            
            -- foreign key
            declare @fkname varchar(100)
            select @fkname = constraint_name from information_schema.table_constraints
            where table_name = @table and constraint_type='FOREIGN KEY'
            
            if ( @fkname is not null ) begin
                insert into @sql(s) values(',')
                insert into @sql(s) values('  FOREIGN KEY (')
                insert into @sql(s)
                    select '   '+COLUMN_NAME+',' from information_schema.key_column_usage
                    where constraint_name = @fkname
                    order by ordinal_position
                -- remove trailing comma
                update @sql set s=left(s,len(s)-1) where id=@@identity
                insert into @sql(s) values ('  ) REFERENCES ')
                insert into @sql(s) 
                    SELECT  
                        OBJECT_NAME(fk.referenced_object_id)
                    FROM 
                        sys.foreign_keys fk
                    INNER JOIN 
                        sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
                    INNER JOIN
                        sys.columns c1 ON fkc.parent_column_id = c1.column_id AND fkc.parent_object_id = c1.object_id
                    INNER JOIN
                        sys.columns c2 ON fkc.referenced_column_id = c2.column_id AND fkc.referenced_object_id = c2.object_id
                    where fk.name = @fkname
                insert into @sql(s) 
                    SELECT  
                        '('+c2.name+')'
                    FROM 
                        sys.foreign_keys fk
                    INNER JOIN 
                        sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
                    INNER JOIN
                        sys.columns c1 ON fkc.parent_column_id = c1.column_id AND fkc.parent_object_id = c1.object_id
                    INNER JOIN
                        sys.columns c2 ON fkc.referenced_column_id = c2.column_id AND fkc.referenced_object_id = c2.object_id
                    where fk.name = @fkname
            end
            
            -- closing bracket
            insert into @sql(s) values( ')' )
            
            -- result!
            select s from @sql order by id
            

            【讨论】:

            • 将此(编辑)重新发布到已接受的答案中可能会很好。这似乎完全符合 SO 的精神。我的回答中的模式和换行符对于全面的一站式人性化解决方案也很好。
            【解决方案10】:

            支持模式:

            这是一个更新版本,修改了 David 等人的出色回答。添加了对命名模式的支持。应该注意的是,如果在各种模式中实际存在同名的表,这可能会中断。另一个改进是使用了官方的QuoteName()函数。

            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'
            ;
            

            ..

            用于 Management Studio:

            对上面的 sql 代码的一个批评是,如果您使用 SSMS 对其进行测试,那么长语句不容易阅读。因此,根据this helpful post,这是另一个版本,在单击网格中单元格的链接后,它经过了一些修改,使眼睛更容易看到。结果更容易识别为 db 中每个表的格式良好的 CREATE TABLE 语句。

            -- 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'
            ;
            

            不强调这一点,但这里是功能等效的示例输出以供比较:

            -- 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]);
            

            ..

            不利因素:

            应该注意的是,由于缺乏对除主键以外的索引的支持,我对此仍然相对不满意。它仍然适合用作简单数据导出或复制的机制。

            【讨论】:

            • 这实际上适用于 Stack Exchange Data Explorer,超级有用!
            【解决方案11】:

            msdb 论坛中有一个 Powershell 脚本,它将为所有表和相关对象编写脚本:

            # Script all tables in a database
            [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") 
                | out-null
            
            $s = new-object ('Microsoft.SqlServer.Management.Smo.Server') '<Servername>'
            $db = $s.Databases['<Database>']
            
            $scrp = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($s)
            $scrp.Options.AppendToFile = $True
            $scrp.Options.ClusteredIndexes = $True
            $scrp.Options.DriAll = $True
            $scrp.Options.ScriptDrops = $False
            $scrp.Options.IncludeHeaders = $False
            $scrp.Options.ToFileOnly = $True
            $scrp.Options.Indexes = $True
            $scrp.Options.WithDependencies = $True
            $scrp.Options.FileName = 'C:\Temp\<Database>.SQL'
            
            foreach($item in $db.Tables) { $tablearray+=@($item) }
            $scrp.Script($tablearray)
            
            Write-Host "Scripting complete"
            

            【讨论】:

            • 当您有权使用 SMO 时,它非常棒。我发现许多系统并非如此,因此纯 INFORMATION_SCHEMA 方法具有一些优势。
            【解决方案12】:

            Show create table in classic asp(处理约束、主键、复制表结构和/或数据...)

            Sql server 显示创建表 来自 Microsoft sql server 的 Mysql 风格的“显示创建表”和“显示创建数据库”命令。 该脚本是用 Microsoft asp 语言编写的,很容易移植到另一种语言。*

            【讨论】:

              【解决方案13】:

              如果您从中生成脚本的应用程序是 .NET 应用程序,您可能需要考虑使用 SMO(Sql 管理对象)。参考此SQL Team link 了解如何使用 SMO 编写对象脚本。

              【讨论】:

                【解决方案14】:

                如果您使用的是管理工作室并打开了查询分析器窗口,您可以将表名拖到查询分析器窗口,然后...宾果游戏!你得到表格脚本。 我没有在 SQL2008 中尝试过这个

                【讨论】:

                • 这是一个简洁的快捷方式,但同样:我需要以编程方式完成。
                【解决方案15】:

                我注意到了 - 在 INFORMATION_SCHEMA.COLUMNS 视图中,CHARACTER_MAXIMUM_LENGTH 为图像和文本等字段类型提供了 2147483647 (2^31-1) 的大小。 ntext 是 2^30-1 (是双字节 unicode 和所有)。

                此大小包含在此查询的输出中,但对于 CREATE 语句中的这些数据类型无效(它们根本不应该具有最大大小值)。因此,除非手动更正由此产生的结果,否则 CREATE 脚本在这些数据类型下将无法工作。

                我想可以修复脚本来解决这个问题,但这超出了我的 SQL 能力。

                【讨论】:

                  【解决方案16】:

                  感谢@Blorgbeard 分享他的脚本。我一定会收藏它以备不时之需。

                  是的,您可以“右键单击”表格并编写 CREATE TABLE 脚本,但是:

                  • a 脚本将包含 加载 的杂碎(对扩展属性感兴趣的人吗?)
                  • 如果您的架构中有 200 多个表,您将需要半天的时间来手动编写脚本。

                  通过将此脚本转换为存储过程,并结合包装脚本,您将有一种很好的自动化方式将您的表格设计转储到源代码控制等中。

                  您的数据库代码的其余部分(SP、FK 索引、触发器等)无论如何都将处于源代码控制之下;)

                  【讨论】:

                  • 我认为 dbproject 可以直接从服务器导入架构,因此您不需要签入创建表语句,并且在 SSMS 中您可以使用“对象资源管理器详细信息”编写多个表的脚本或右键单击对象资源管理器中的数据库并选择 Tasks->Generate scripts
                  猜你喜欢
                  • 2012-09-22
                  • 2018-07-17
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-01
                  • 2019-05-05
                  相关资源
                  最近更新 更多