Sao chép cấu trúc hoàn chỉnh của một bảng


33

Sử dụng một số phương pháp, khi bạn tạo một bản sao của bảng, bạn sẽ mất các chỉ mục, PK, FK, v.v. Ví dụ: trong SQL Server tôi có thể nói:

select * into dbo.table2 from dbo.table1;

Đây chỉ là một bản sao đơn giản của bảng; tất cả các chỉ mục / ràng buộc bị thiếu. Làm cách nào để sao chép cấu trúc bảng (không sử dụng bản sao lưu)?

Tôi chủ yếu tìm cách làm điều này bằng tay, nhưng nếu không thể, tôi sẽ chấp nhận bất kỳ giải pháp nào.

Câu trả lời:


30

Tất nhiên, bạn có thể tạo một bảng tương đối dễ dàng bằng giao diện người dùng:

nhập mô tả hình ảnh ở đây

Điều này sẽ xuất ra một CREATE TABLEtập lệnh và bạn chỉ phải tìm kiếm và thay thế tên cũ bằng tên mới (và xác minh rằng một đối tượng với tên mới không tồn tại).

Nhưng nếu bạn đang cố gắng tự động hóa việc này (ví dụ: tạo tập lệnh tạo bảng trong mã), thì nó sẽ cồng kềnh hơn một chút. Tùy chọn kịch bản ở trên không chỉ kéo toàn bộ CREATE TABLEDDL từ một vị trí trong siêu dữ liệu; nó thực hiện một loạt các phép thuật đằng sau hậu trường trong mã để tạo CREATE TABLEtập lệnh cuối cùng (bạn có thể sử dụng Profiler để xem nơi nó lấy dữ liệu của nó, nhưng bạn không thể thấy cách nó lắp ráp nó). Tôi đề nghị một tùy chọn cho việc này:

http://connect.microsoft.com/QueryServer/feedback/details/273934

Tuy nhiên, điều này đã được đáp ứng với rất ít phiếu bầu và nhanh chóng bị Microsoft bắn hạ. Bạn có thể thấy đáng giá hơn nhiều khi sử dụng công cụ của bên thứ 3 để tạo lược đồ ( Tôi đã viết blog về điều này ).

Trong SQL Server 2012, có các hàm siêu dữ liệu mới cho phép bạn tiến gần hơn nhiều so với công việc bạn phải làm trong năm 2005, 2008 và 2008 R2, ghép các thông tin cột từ siêu dữ liệu (ví dụ như có rất nhiều cảnh báo thập phân bạn phải thêm độ chính xác / tỷ lệ, nếu [n [var [char]] bạn phải thêm thông số độ dài, nếu n [var] char bạn phải cắt max_length một nửa, nếu đó là MAX bạn phải thay đổi -1 thành MAX, v.v.). Trong SQL Server 2012, phần này dễ hơn một chút:

SELECT name, system_type_name, is_nullable FROM
  sys.dm_exec_describe_first_result_set('select * from sys.objects', NULL, 0)

Các kết quả:

name                   system_type_name  is_nullable
--------------------   ----------------  -----------
name                   nvarchar(128)     0
object_id              int               0
principal_id           int               1
schema_id              int               0
parent_object_id       int               0
type                   char(2)           0
type_desc              nvarchar(60)      1
create_date            datetime          0
modify_date            datetime          0
is_ms_shipped          bit               0
is_published           bit               0
is_schema_published    bit               0

Tôi cũng đã viết về điều này.

Có thể cho rằng điều này gần với CREATE TABLEtuyên bố được nhắm mục tiêu của bạn hơn là một cách tiếp cận phức tạp bằng cách sử dụng sys.columns, nhưng vẫn còn rất nhiều việc phải làm. Các khóa, ràng buộc, tùy chọn văn bản trong hàng, thông tin nhóm, cài đặt nén, chỉ mục, v.v ... Đó là một danh sách rất dài và một lần nữa tôi sẽ đề nghị bạn xem xét một công cụ của bên thứ 3 thay vì có nguy cơ lặp lại tương tự được sử dụng, phát minh lại bánh xe.

Tất cả đã nói, nếu bạn cần làm điều này thông qua mã nhưng bạn có thể làm điều đó bên ngoài SQL Server, bạn có thể xem xét SMO / PowerShell. Xem mẹo nàyphương thức Scripter.Script () .


Xin lưu ý rằng sys.dm_exec_describe_first_result_set sẽ mang lại cho bạn nvarchar (27) thay vì datetime2 nếu được thực thi trên OLEDB.
Alsin

Điều này không có nghĩa là đối nghịch hay tiêu cực, nhưng loại điều này là lý do tại sao tôi đã chuyển đến Postgres sau 20 năm với SQL. Giải pháp của Postgres là: CREATE TABLE tbl2 (THÍCH tbl1 BAO GỒM TẤT CẢ); - bảng trùng lặp bao gồm tất cả các bình luận chỉ mục, v.v.
Damien Sawyer

@DamienSawyer Công bằng mà nói, tạo ra một loạt các bảng giống hệt nhau có cùng chỉ mục và mọi thứ khác đều có mùi thiết kế. Và có rất nhiều công cụ của bên thứ 3 (một số miễn phí, một số nguồn mở) có thể giúp với điều đó khi bạn thực sự cần nó.
Aaron Bertrand

Chắc chắn, @AaronBertrand điều đó rất đúng trong nhiều trường hợp, đặc biệt là trong các lược đồ kiểu 3NF CRUD phổ biến. Tuy nhiên, đôi khi chúng tôi sử dụng cơ sở dữ liệu ít cứng nhắc hơn, ví dụ như kết hợp và dọn dẹp dữ liệu từ các nguồn không chính thức như CSV để được di chuyển vào hệ thống sản xuất. Để so sánh, một trong những lý do Excel là tuyệt vời là vì trong khi một bảng tính có thể trở nên phức tạp, thì nó lại có nghi thức rất thấp để làm rất đơn giản. Một mảnh giấy có thể được sử dụng như một hợp đồng mua nhà và viết nguệch ngoạc một danh sách mua sắm.
Damien Sawyer

@DamienSawyer Và khi bạn có một quy trình trung gian trong đó thực chất là một bảng dàn dựng, tôi cho rằng nó không phải bao gồm tất cả các chỉ mục, các ràng buộc, các thuộc tính mở rộng, v.v. tồn tại trong bảng nó được mô phỏng theo. Hành vi mặc định có trường hợp sử dụng rất hợp lệ, mặc dù các trường hợp sử dụng khác có thể tồn tại.
Aaron Bertrand

9

tôi đã viết sp này để tự động tạo lược đồ với tất cả mọi thứ, pk, fk, phân vùng, ràng buộc ...

QUAN TRỌNG!! trước khi thực hiện

create type TestTableType as table (ObjectID int)

đây SP

    SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


    --*************************************************************************************************'
--    La procedura crea lo script di una tabella
--    Tabella   : xxxxx
--    Creata da : E.Mantovanelli
--    Data creazione : 28-06-2012
--    Data modifica: 28-06-2012
--*************************************************************************************************'

/*
    --      ID----|-----Data-----|--    User        ---------   | ----  Note
                        20-11-2013      E.Mantovanelli                  distinzione schema delle tabelle
                                                                        estrazione da db selezionato
                                                                        aggiunta estrazione partizione
*/

CREATE PROCEDURE [dbo].[util_ScriptTable] 
     @DBName SYSNAME
    ,@schema sysname
    ,@TableName SYSNAME
    ,@IncludeConstraints BIT = 1
    ,@IncludeIndexes BIT = 1
    ,@NewTableSchema sysname
    ,@NewTableName SYSNAME = NULL
    ,@UseSystemDataTypes BIT = 0
    ,@script varchar(max) output
AS 
BEGIN try
    if not exists (select * from sys.types where name = 'TestTableType')
        create type TestTableType as table (ObjectID int)--drop type TestTableType

    declare @sql nvarchar(max)

    DECLARE @MainDefinition TABLE (FieldValue VARCHAR(200))
    --DECLARE @DBName SYSNAME
    DECLARE @ClusteredPK BIT
    DECLARE @TableSchema NVARCHAR(255)

    --SET @DBName = DB_NAME(DB_ID())
    SELECT @TableName = name FROM sysobjects WHERE id = OBJECT_ID(@TableName)

    DECLARE @ShowFields TABLE (FieldID INT IDENTITY(1,1)
                                        ,DatabaseName VARCHAR(100)
                                        ,TableOwner VARCHAR(100)
                                        ,TableName VARCHAR(100)
                                        ,FieldName VARCHAR(100)
                                        ,ColumnPosition INT
                                        ,ColumnDefaultValue VARCHAR(100)
                                        ,ColumnDefaultName VARCHAR(100)
                                        ,IsNullable BIT
                                        ,DataType VARCHAR(100)
                                        ,MaxLength varchar(10)
                                        ,NumericPrecision INT
                                        ,NumericScale INT
                                        ,DomainName VARCHAR(100)
                                        ,FieldListingName VARCHAR(110)
                                        ,FieldDefinition CHAR(1)
                                        ,IdentityColumn BIT
                                        ,IdentitySeed INT
                                        ,IdentityIncrement INT
                                        ,IsCharColumn BIT 
                                        ,IsComputed varchar(255))

    DECLARE @HoldingArea TABLE(FldID SMALLINT IDENTITY(1,1)
                                        ,Flds VARCHAR(4000)
                                        ,FldValue CHAR(1) DEFAULT(0))

    DECLARE @PKObjectID TABLE(ObjectID INT)

    DECLARE @Uniques TABLE(ObjectID INT)

    DECLARE @HoldingAreaValues TABLE(FldID SMALLINT IDENTITY(1,1)
                                                ,Flds VARCHAR(4000)
                                                ,FldValue CHAR(1) DEFAULT(0))

    DECLARE @Definition TABLE(DefinitionID SMALLINT IDENTITY(1,1)
                                        ,FieldValue VARCHAR(200))


  set @sql=
  '
  use '+@DBName+'
  SELECT distinct DB_NAME()
            ,TABLE_SCHEMA
            ,TABLE_NAME
            ,''[''+COLUMN_NAME+'']'' as COLUMN_NAME
            ,CAST(ORDINAL_POSITION AS INT)
            ,COLUMN_DEFAULT
            ,dobj.name AS ColumnDefaultName
            ,CASE WHEN c.IS_NULLABLE = ''YES'' THEN 1 ELSE 0 END
            ,DATA_TYPE
            ,case CHARACTER_MAXIMUM_LENGTH when -1 then ''max'' else CAST(CHARACTER_MAXIMUM_LENGTH AS varchar) end--CAST(CHARACTER_MAXIMUM_LENGTH AS INT)
            ,CAST(NUMERIC_PRECISION AS INT)
            ,CAST(NUMERIC_SCALE AS INT)
            ,DOMAIN_NAME
            ,COLUMN_NAME + '',''
            ,'''' AS FieldDefinition
            ,CASE WHEN ic.object_id IS NULL THEN 0 ELSE 1 END AS IdentityColumn
            ,CAST(ISNULL(ic.seed_value,0) AS INT) AS IdentitySeed
            ,CAST(ISNULL(ic.increment_value,0) AS INT) AS IdentityIncrement
            ,CASE WHEN st.collation_name IS NOT NULL THEN 1 ELSE 0 END AS IsCharColumn 
            ,cc.definition 
            FROM INFORMATION_SCHEMA.COLUMNS c
            JOIN sys.columns sc ON  c.TABLE_NAME = OBJECT_NAME(sc.object_id) AND c.COLUMN_NAME = sc.Name
            LEFT JOIN sys.identity_columns ic ON c.TABLE_NAME = OBJECT_NAME(ic.object_id) AND c.COLUMN_NAME = ic.Name
            JOIN sys.types st ON COALESCE(c.DOMAIN_NAME,c.DATA_TYPE) = st.name
            LEFT OUTER JOIN sys.objects dobj ON dobj.object_id = sc.default_object_id AND dobj.type = ''D''
            left join sys.computed_columns cc on c.TABLE_NAME=OBJECT_NAME(cc.object_id) and sc.column_id=cc.column_id
    WHERE c.TABLE_NAME = @TableName and c.TABLE_SCHEMA=@schema 
    ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION
    '

  print @sql
  INSERT INTO @ShowFields( DatabaseName
                                    ,TableOwner
                                    ,TableName
                                    ,FieldName
                                    ,ColumnPosition
                                    ,ColumnDefaultValue
                                    ,ColumnDefaultName
                                    ,IsNullable
                                    ,DataType
                                    ,MaxLength
                                    ,NumericPrecision
                                    ,NumericScale
                                    ,DomainName
                                    ,FieldListingName
                                    ,FieldDefinition
                                    ,IdentityColumn
                                    ,IdentitySeed
                                    ,IdentityIncrement
                                    ,IsCharColumn
                                    ,IsComputed)

    exec sp_executesql @sql,
                       N'@TableName varchar(50),@schema varchar(50)',
                       @TableName=@TableName,@schema=@schema            
    /*
    SELECT @DBName--DB_NAME()
            ,TABLE_SCHEMA
            ,TABLE_NAME
            ,COLUMN_NAME
            ,CAST(ORDINAL_POSITION AS INT)
            ,COLUMN_DEFAULT
            ,dobj.name AS ColumnDefaultName
            ,CASE WHEN c.IS_NULLABLE = 'YES' THEN 1 ELSE 0 END
            ,DATA_TYPE
            ,CAST(CHARACTER_MAXIMUM_LENGTH AS INT)
            ,CAST(NUMERIC_PRECISION AS INT)
            ,CAST(NUMERIC_SCALE AS INT)
            ,DOMAIN_NAME
            ,COLUMN_NAME + ','
            ,'' AS FieldDefinition
            ,CASE WHEN ic.object_id IS NULL THEN 0 ELSE 1 END AS IdentityColumn
            ,CAST(ISNULL(ic.seed_value,0) AS INT) AS IdentitySeed
            ,CAST(ISNULL(ic.increment_value,0) AS INT) AS IdentityIncrement
            ,CASE WHEN st.collation_name IS NOT NULL THEN 1 ELSE 0 END AS IsCharColumn 
            FROM INFORMATION_SCHEMA.COLUMNS c
            JOIN sys.columns sc ON  c.TABLE_NAME = OBJECT_NAME(sc.object_id) AND c.COLUMN_NAME = sc.Name
            LEFT JOIN sys.identity_columns ic ON c.TABLE_NAME = OBJECT_NAME(ic.object_id) AND c.COLUMN_NAME = ic.Name
            JOIN sys.types st ON COALESCE(c.DOMAIN_NAME,c.DATA_TYPE) = st.name
            LEFT OUTER JOIN sys.objects dobj ON dobj.object_id = sc.default_object_id AND dobj.type = 'D'

    WHERE c.TABLE_NAME = @TableName
    ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION
    */
    SELECT TOP 1 @TableSchema = TableOwner FROM @ShowFields

    INSERT INTO @HoldingArea (Flds) VALUES('(')

    INSERT INTO @Definition(FieldValue)VALUES('CREATE TABLE ' + CASE WHEN @NewTableName IS NOT NULL THEN @DBName + '.' + @NewTableSchema + '.' + @NewTableName ELSE @DBName + '.' + @TableSchema + '.' + @TableName END)
    INSERT INTO @Definition(FieldValue)VALUES('(')
    INSERT INTO @Definition(FieldValue)
    SELECT   CHAR(10) + FieldName + ' ' + 
        --CASE WHEN DomainName IS NOT NULL AND @UseSystemDataTypes = 0 THEN DomainName + CASE WHEN IsNullable = 1 THEN ' NULL ' ELSE ' NOT NULL ' END ELSE UPPER(DataType) +CASE WHEN IsCharColumn = 1 THEN '(' + CAST(MaxLength AS VARCHAR(10)) + ')' ELSE '' END +CASE WHEN IdentityColumn = 1 THEN ' IDENTITY(' + CAST(IdentitySeed AS VARCHAR(5))+ ',' + CAST(IdentityIncrement AS VARCHAR(5)) + ')' ELSE '' END +CASE WHEN IsNullable = 1 THEN ' NULL ' ELSE ' NOT NULL ' END +CASE WHEN ColumnDefaultName IS NOT NULL AND @IncludeConstraints = 1 THEN 'CONSTRAINT [' + ColumnDefaultName + '] DEFAULT' + UPPER(ColumnDefaultValue) ELSE '' END END + CASE WHEN FieldID = (SELECT MAX(FieldID) FROM @ShowFields) THEN '' ELSE ',' END 

        CASE WHEN DomainName IS NOT NULL AND @UseSystemDataTypes = 0 THEN DomainName + 
            CASe WHEN IsNullable = 1 THEN ' NULL ' 
            ELSE ' NOT NULL ' 
            END 
        ELSE 
            case when IsComputed is null then
                UPPER(DataType) +
                CASE WHEN IsCharColumn = 1 THEN '(' + CAST(MaxLength AS VARCHAR(10)) + ')' 
                ELSE 
                    CASE WHEN DataType = 'numeric' THEN '(' + CAST(NumericPrecision AS VARCHAR(10))+','+ CAST(NumericScale AS VARCHAR(10)) + ')' 
                    ELSE
                        CASE WHEN DataType = 'decimal' THEN '(' + CAST(NumericPrecision AS VARCHAR(10))+','+ CAST(NumericScale AS VARCHAR(10)) + ')' 
                        ELSE '' 
                        end  
                    end 
                END +
                CASE WHEN IdentityColumn = 1 THEN ' IDENTITY(' + CAST(IdentitySeed AS VARCHAR(5))+ ',' + CAST(IdentityIncrement AS VARCHAR(5)) + ')' 
                ELSE '' 
                END +
                CASE WHEN IsNullable = 1 THEN ' NULL ' 
                ELSE ' NOT NULL ' 
                END +
                CASE WHEN ColumnDefaultName IS NOT NULL AND @IncludeConstraints = 1 THEN 'CONSTRAINT [' + replace(ColumnDefaultName,@TableName,@NewTableName) + '] DEFAULT' + UPPER(ColumnDefaultValue) 
                ELSE '' 
                END 
            else
                ' as '+IsComputed+' '
            end
        END + 
        CASE WHEN FieldID = (SELECT MAX(FieldID) FROM @ShowFields) THEN '' 
        ELSE ',' 
        END 

    FROM    @ShowFields

    IF @IncludeConstraints = 1
        BEGIN    

        set @sql=
        '
        use '+@DBName+'
        SELECT  distinct  '',CONSTRAINT ['' + replace(name,@TableName,@NewTableName) + ''] FOREIGN KEY ('' + ParentColumns + '') REFERENCES ['' + ReferencedObject + '']('' + ReferencedColumns + '')'' 
           FROM ( SELECT   ReferencedObject = OBJECT_NAME(fk.referenced_object_id), ParentObject = OBJECT_NAME(parent_object_id),fk.name
                ,   REVERSE(SUBSTRING(REVERSE((   SELECT cp.name + '',''   
                FROM   sys.foreign_key_columns fkc   
                JOIN sys.columns cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id   
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('''')   )), 2, 8000)) ParentColumns,   
                REVERSE(SUBSTRING(REVERSE((   SELECT cr.name + '',''   
                FROM   sys.foreign_key_columns fkc  
                JOIN sys.columns cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('''')   )), 2, 8000)) ReferencedColumns   
                FROM sys.foreign_keys fk    
                    inner join sys.schemas s on fk.schema_id=s.schema_id and s.name=@schema) a    
            WHERE ParentObject = @TableName    
        '

        print @sql

        INSERT INTO @Definition(FieldValue)
        exec sp_executesql @sql,
                   N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50)',
                       @TableName=@TableName,@NewTableName=@NewTableName,@schema=@schema
            /*
           SELECT    ',CONSTRAINT [' + name + '] FOREIGN KEY (' + ParentColumns + ') REFERENCES [' + ReferencedObject + '](' + ReferencedColumns + ')'  
           FROM ( SELECT   ReferencedObject = OBJECT_NAME(fk.referenced_object_id), ParentObject = OBJECT_NAME(parent_object_id),fk.name
                ,   REVERSE(SUBSTRING(REVERSE((   SELECT cp.name + ','   
                FROM   sys.foreign_key_columns fkc   
                JOIN sys.columns cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id   
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('')   )), 2, 8000)) ParentColumns,   
                REVERSE(SUBSTRING(REVERSE((   SELECT cr.name + ','   
                FROM   sys.foreign_key_columns fkc  
                JOIN sys.columns cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('')   )), 2, 8000)) ReferencedColumns   
                FROM sys.foreign_keys fk    ) a    
            WHERE ParentObject = @TableName    
            */

            set @sql=
            '
            use '+@DBName+'
            SELECT distinct '',CONSTRAINT ['' + replace(c.name,@TableName,@NewTableName) + ''] CHECK '' + definition 
            FROM sys.check_constraints c join sys.schemas s on c.schema_id=s.schema_id and s.name=@schema    
            WHERE OBJECT_NAME(parent_object_id) = @TableName
            '

            print @sql
            INSERT INTO @Definition(FieldValue) 
            exec sp_executesql @sql,
                               N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50)',
                       @TableName=@TableName,@NewTableName=@NewTableName,@schema=@schema
            /*
            SELECT ',CONSTRAINT [' + name + '] CHECK ' + definition FROM sys.check_constraints    
            WHERE OBJECT_NAME(parent_object_id) = @TableName
            */

            set @sql=
            '
            use '+@DBName+'
            SELECT DISTINCT  PKObject = cco.object_id 
            FROM    sys.key_constraints cco    
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id    
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            WHERE    OBJECT_NAME(parent_object_id) = @TableName    AND  i.type = 1 AND    is_primary_key = 1
            '
            print @sql
            INSERT INTO @PKObjectID(ObjectID) 
            exec sp_executesql @sql,
                               N'@TableName varchar(50),@schema varchar(50)',
                               @TableName=@TableName,@schema=@schema
            /*
            SELECT DISTINCT  PKObject = cco.object_id 
            FROM    sys.key_constraints cco    
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id    
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            WHERE    OBJECT_NAME(parent_object_id) = @TableName    AND  i.type = 1 AND    is_primary_key = 1
            */

            set @sql=
            '
            use '+@DBName+'
            SELECT DISTINCT    PKObject = cco.object_id
            FROM    sys.key_constraints cco   
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id  
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            WHERE    OBJECT_NAME(parent_object_id) = @TableName AND  i.type = 2 AND    is_primary_key = 0 AND    is_unique_constraint = 1
            '
            print @sql
            INSERT INTO @Uniques(ObjectID)
            exec sp_executesql @sql,
                               N'@TableName varchar(50),@schema varchar(50)',
                               @TableName=@TableName,@schema=@schema
            /*
            SELECT DISTINCT    PKObject = cco.object_id
            FROM    sys.key_constraints cco   
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id  
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            WHERE    OBJECT_NAME(parent_object_id) = @TableName AND  i.type = 2 AND    is_primary_key = 0 AND    is_unique_constraint = 1
            */

            SET @ClusteredPK = CASE WHEN @@ROWCOUNT > 0 THEN 1 ELSE 0 END

            declare @t TestTableType
            insert @t select * from @PKObjectID
            declare @u TestTableType
            insert @u select * from @Uniques

            set @sql=
            '
            use '+@DBName+'
            SELECT distinct '',CONSTRAINT '' + replace(cco.name,@TableName,@NewTableName) + CASE type WHEN ''PK'' THEN '' PRIMARY KEY '' + CASE WHEN pk.ObjectID IS NULL THEN '' NONCLUSTERED '' ELSE '' CLUSTERED '' END  WHEN ''UQ'' THEN '' UNIQUE '' END + CASE WHEN u.ObjectID IS NOT NULL THEN '' NONCLUSTERED '' ELSE '''' END 
            + ''(''+REVERSE(SUBSTRING(REVERSE(( SELECT   c.name +  + CASE WHEN cc.is_descending_key = 1 THEN '' DESC'' ELSE '' ASC'' END + '',''    
            FROM   sys.key_constraints ccok   
            LEFT JOIN sys.index_columns cc ON ccok.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id
            LEFT JOIN sys.columns c ON cc.object_id = c.object_id AND cc.column_id = c.column_id 
            LEFT JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id  
            WHERE i.object_id = ccok.parent_object_id AND   ccok.object_id = cco.object_id    
            order by key_ordinal FOR XML PATH(''''))), 2, 8000)) + '')''
            FROM sys.key_constraints cco 
            inner join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            LEFT JOIN @U u ON cco.object_id = u.objectID
            LEFT JOIN @t pk ON cco.object_id = pk.ObjectID    
            WHERE    OBJECT_NAME(cco.parent_object_id) = @TableName 

            '

            print @sql
            INSERT INTO @Definition(FieldValue)
            exec sp_executesql @sql,
                               N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50),@t TestTableType readonly,@u TestTableType readonly',
                               @TableName=@TableName,@NewTableName=@NewTableName,@schema=@schema,@t=@t,@u=@u

            /*
            SELECT ',CONSTRAINT ' + name + CASE type WHEN 'PK' THEN ' PRIMARY KEY ' + CASE WHEN pk.ObjectID IS NULL THEN ' NONCLUSTERED ' ELSE ' CLUSTERED ' END  WHEN 'UQ' THEN ' UNIQUE ' END + CASE WHEN u.ObjectID IS NOT NULL THEN ' NONCLUSTERED ' ELSE '' END 
            + '(' +REVERSE(SUBSTRING(REVERSE(( SELECT   c.name +  + CASE WHEN cc.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END + ','    
            FROM   sys.key_constraints ccok   
            LEFT JOIN sys.index_columns cc ON ccok.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id
           LEFT JOIN sys.columns c ON cc.object_id = c.object_id AND cc.column_id = c.column_id 
           LEFT JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id  
           WHERE i.object_id = ccok.parent_object_id AND   ccok.object_id = cco.object_id    FOR XML PATH(''))), 2, 8000)) + ')'
           FROM sys.key_constraints cco 
           LEFT JOIN @PKObjectID pk ON cco.object_id = pk.ObjectID    
           LEFT JOIN @Uniques u ON cco.object_id = u.objectID
           WHERE    OBJECT_NAME(cco.parent_object_id) = @TableName 
           */
        END

        INSERT INTO @Definition(FieldValue) VALUES(')')

        set @sql=
        '
        use '+@DBName+'
        select '' on '' + d.name + ''([''+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)
                          join sys.schemas s on t.schema_id=s.schema_id
                          join sys.data_spaces d on i.data_space_id=d.data_space_id
        where t.name=@TableName and s.name=@schema
        order by key_ordinal
        '

        print 'x'
        print @sql
        INSERT INTO @Definition(FieldValue) 
        exec sp_executesql @sql,
                           N'@TableName varchar(50),@schema varchar(50)',
                           @TableName=@TableName,@schema=@schema

        IF @IncludeIndexes = 1
        BEGIN
            set @sql=
            '
            use '+@DBName+'
            SELECT distinct '' CREATE '' + i.type_desc + '' INDEX ['' + replace(i.name COLLATE SQL_Latin1_General_CP1_CI_AS,@TableName,@NewTableName) + ''] ON '+@DBName+'.'+@NewTableSchema+'.'+@NewTableName+' ('' 
            +   REVERSE(SUBSTRING(REVERSE((   SELECT name + CASE WHEN sc.is_descending_key = 1 THEN '' DESC'' ELSE '' ASC'' END + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=0
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000)) + '')''+
            ISNULL( '' include (''+REVERSE(SUBSTRING(REVERSE((   SELECT name + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=1
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000))+'')'' ,'''')+''''    
            FROM sys.indexes i join sys.tables t on i.object_id=t.object_id
                               join sys.schemas s on t.schema_id=s.schema_id   
            AND CASE WHEN @ClusteredPK = 1 AND is_primary_key = 1 AND i.type = 1 THEN 0 ELSE 1 END = 1   AND is_unique_constraint = 0   AND is_primary_key = 0 
                where t.name=@TableName and s.name=@schema
            '

            print @sql
            INSERT INTO @Definition(FieldValue)    
            exec sp_executesql @sql,
                               N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50), @ClusteredPK bit',
                               @TableName=@TableName,@NewTableName=@NewTableName,@schema=@schema,@ClusteredPK=@ClusteredPK

        END 

            /*

                SELECT   'CREATE ' + type_desc + ' INDEX [' + [name] COLLATE SQL_Latin1_General_CP1_CI_AS + '] ON [' +  OBJECT_NAME(object_id) + '] (' +   REVERSE(SUBSTRING(REVERSE((   SELECT name + CASE WHEN sc.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END + ','   
                FROM  sys.index_columns sc  
                JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
                WHERE  OBJECT_NAME(sc.object_id) = @TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                ORDER BY index_column_id ASC   FOR XML PATH('')    )), 2, 8000)) + ')'    
                FROM sys.indexes i    
                WHERE   OBJECT_NAME(object_id) = @TableName
                AND CASE WHEN @ClusteredPK = 1 AND is_primary_key = 1 AND type = 1 THEN 0 ELSE 1 END = 1   AND is_unique_constraint = 0   AND is_primary_key = 0 

            */

            INSERT INTO @MainDefinition(FieldValue)   
            SELECT FieldValue FROM @Definition    
            ORDER BY DefinitionID ASC 

            ----------------------------------

            declare @q  varchar(max)

            set @q=(select replace((SELECT FieldValue FROM @MainDefinition FOR XML PATH('')),'</FieldValue>',''))

            set @script=(select REPLACE(@q,'<FieldValue>',''))
            --drop type TestTableType
END try
-- ##############################################################################################################################################################################
BEGIN CATCH        
    BEGIN
        -- INIZIO  Procedura in errore =========================================================================================================================================================
            PRINT '***********************************************************************************************************************************************************' 
            PRINT 'ErrorNumber               : ' + CAST(ERROR_NUMBER() AS NVARCHAR(MAX))
            PRINT 'ErrorSeverity             : ' + CAST(ERROR_SEVERITY() AS NVARCHAR(MAX)) 
            PRINT 'ErrorState                : ' + CAST(ERROR_STATE() AS NVARCHAR(MAX)) 
            PRINT 'ErrorLine                 : ' + CAST(ERROR_LINE() AS NVARCHAR(MAX)) 
            PRINT 'ErrorMessage              : ' + CAST(ERROR_MESSAGE() AS NVARCHAR(MAX))
            PRINT '***********************************************************************************************************************************************************' 
        -- FINE  Procedura in errore =========================================================================================================================================================
    END 
        set @script=''
    return -1
END CATCH   
-- ##############################################################################################################################################################################   

để thực hiện nó:

declare @s varchar(max)
exec [util_ScriptTable]   'db','schema_source','table_source',1,1,'schema_dest','tab_dest',0,@s output
select @s

nó không hoạt động !!
itzik Paz

Tôi đã cập nhật tập lệnh: hỗ trợ cột văn bản cố định và thêm khả năng Tạo bảng và sao chép dữ liệu. Nó có thể được sử dụng thay vì 'CHỌN * VÀO NewTable TỪ OldTable', sao chép dữ liệu, nhưng không phải là lược đồ. Xem gist.github.com/MNF/eb905c7ec215670a3abc62f9c2cf9d7b
MiFreidgeim SO-ngừng ác vào

4

Điều này có thể là sử dụng búa khoan để đặt một cái đinh vào tường, nhưng với độ rộng của câu hỏi tôi nghĩ đó là một lựa chọn hợp lệ để đề cập.

Nếu bạn đang sử dụng SQL Server 2012 SP4 +, 2014 SP2 + hoặc 2016 SP1 +, bạn có thể tận dụng DBCC CLONEDATABASEđể tạo một bản sao chỉ lược đồ của cơ sở dữ liệu của bạn. Điều này lý tưởng để tạo các bản sao lược đồ toàn diện của nhiều bảng và có thể giảm bớt nhu cầu "tự động hóa" quá trình lặp qua một loạt các bảng, nhưng được cảnh báo rằng tất cả các bản sao bảng sẽ được tạo bên trong cơ sở dữ liệu chỉ đọc mới .

Các bảng này sẽ bao gồm khóa ngoại, khóa chính, chỉ mục và các ràng buộc. Chúng cũng sẽ bao gồm số liệu thống kê và lưu trữ truy vấn (trừ khi bạn chỉ định NO_STATISTICSNO_QUERYSTORE).

Cú pháp là

DBCC CLONEDATABASE (source_database_name, target_database_name)[WITH [NO_STATISTICS][,NO_QUERYSTORE]] 

Ngoài ra còn có một vài lưu ý khác, đó là Brent Ozar có một bài đăng tuyệt vời , nhưng tất cả thực sự nắm rõ cách thức và lý do tại sao bạn muốn tạo các bản sao của bảng về việc liệu có bất kỳ sự tinh tế nào là phá vỡ thỏa thuận hay không .


3

Bạn có thể sử dụng lệnh "Tạo tập lệnh" trong SQL Server Management Studio để lấy tập lệnh có thể tạo bảng của bạn, bao gồm các chỉ mục, trình kích hoạt, khóa ngoại, v.v.

Trong SSMS

  • Nhấp chuột phải vào cơ sở dữ liệu của bảng
  • Chọn Nhiệm vụ -> Tạo tập lệnh
  • Chọn "Chọn đối tượng cơ sở dữ liệu cụ thể"
  • Mở rộng danh sách "Bảng" và chọn hộp kiểm bên cạnh bảng bạn muốn tạo tập lệnh
  • Nhấp vào "Tiếp theo" để chuyển đến trang tiếp theo của trình hướng dẫn
  • Đặt các tùy chọn lưu như bạn muốn, sau đó nhấp vào nút "Nâng cao"
  • Đặt các tùy chọn nâng cao như bạn muốn. Cụ thể, trong "Tùy chọn bảng / chế độ xem", lưu ý rằng (theo mặc định) các chỉ mục, trình kích hoạt và chỉ mục toàn văn bản không được viết theo kịch bản; nếu bạn muốn những thứ đó, hãy chuyển chúng từ "Sai" sang "Đúng"
  • Khi hoàn tất, nhấp vào "OK" để lưu các tùy chọn nâng cao của bạn và "Tiếp theo" để xem lại các lựa chọn của bạn. Nhấp vào "Tiếp theo" lần nữa để thực sự tạo tập lệnh.

Sau đó, bạn có thể chỉnh sửa để bao gồm chỉ những gì bạn cần trong cơ sở dữ liệu đích của bạn.


0

Đây là một phiên bản dựa trên bản của E.Mantovanelli trong chủ đề này. Điều này sửa một vấn đề trong đó một chỉ mục duy nhất không bao gồm từ khóa UNIQUE trong tập lệnh kết quả. Nó cũng thêm các tham số để một bảng có thể được tạo mà không có các chỉ mục không được nhóm hoặc bạn chỉ có thể tạo kịch bản cho các chỉ mục không được phân cụm. Tôi sử dụng điều này để tạo một bảng giai đoạn, tải nó thêm các chỉ mục không được nhóm sau đó thực hiện chuyển đổi bảng, cho phép tải chạy nhanh hơn và các chỉ mục không bị phân mảnh.

SET ANSI_NULLS ON;
GO

SET QUOTED_IDENTIFIER ON;
GO

--*************************************************************************************************'
--    La procedura crea lo script di una tabella
--    Tabella   : xxxxx
--    Creata da : E.Mantovanelli
--    Data creazione : 28-06-2012
--    Data modifica: 28-06-2012
--*************************************************************************************************'

/*
    --      ID----|-----Data-----|--    User        ---------   | ----  Note
                        20-11-2013      E.Mantovanelli                  distinzione schema delle tabelle
                                                                        estrazione da db selezionato
                                                                        aggiunta estrazione partizione
*/
--*************************************************************************************************'
--    Creates a copy of a table with optionally all indexes and constraints depending on parameters
--    Updated by : Brent Willis
--    Date Updated : 09-11-2019
--    Changes: Added the ability to create a table with clustered index and constraints only or to 
--             CREATE just the non-clustered indexes. This is helpful so a table can be created, 
--             loaded then non-clusted indexes added so it can them be swapped into a partitioned 
--             table with freshly created indexes to lower fragmentation. 
--
--             Also fixed an issue when a unique index was defined the index resulting table was not unique. 
--*************************************************************************************************'

ALTER PROCEDURE dbo.util_ScriptTable
    @DBName                sysname
  , @schema                sysname
  , @TableName             sysname
  , @includeTable          Bit     = 1
  , @IncludeConstraints    Bit     = 1
  , @IncludeClusteredIndex Bit     = 1
  , @IncludeIndexes        Bit     = 1
  , @NewTableSchema        sysname
  , @NewTableName          sysname = NULL
  , @UseSystemDataTypes    Bit     = 0
  , @script                Varchar(MAX) OUTPUT
AS
    BEGIN TRY
        IF NOT EXISTS (SELECT * FROM sys.types WHERE name = 'TestTableType')
            CREATE TYPE TestTableType AS TABLE (ObjectID Int); --drop type TestTableType

        DECLARE @sql NVarchar(MAX);

        DECLARE @MainDefinition Table (FieldValue Varchar(200));

        --DECLARE @DBName SYSNAME
        DECLARE @ClusteredPK Bit;
        DECLARE @TableSchema NVarchar(255);

        --SET @DBName = DB_NAME(DB_ID())
        SELECT @TableName = name FROM sys.sysobjects WHERE id = Object_Id(@TableName);

        DECLARE @ShowFields Table (FieldID            Int IDENTITY(1, 1)
                                 , DatabaseName       Varchar(100)
                                 , TableOwner         Varchar(100)
                                 , TableName          Varchar(100)
                                 , FieldName          Varchar(100)
                                 , ColumnPosition     Int
                                 , ColumnDefaultValue Varchar(100)
                                 , ColumnDefaultName  Varchar(100)
                                 , IsNullable         Bit
                                 , DataType           Varchar(100)
                                 , MaxLength          Varchar(10)
                                 , NumericPrecision   Int
                                 , NumericScale       Int
                                 , DomainName         Varchar(100)
                                 , FieldListingName   Varchar(110)
                                 , FieldDefinition    Char(1)
                                 , IdentityColumn     Bit
                                 , IdentitySeed       Int
                                 , IdentityIncrement  Int
                                 , IsCharColumn       Bit
                                 , IsComputed         Varchar(255));

        DECLARE @HoldingArea Table (FldID SmallInt IDENTITY(1, 1), Flds Varchar(4000), FldValue Char(1) DEFAULT (0));

        DECLARE @PKObjectID Table (ObjectID Int);

        DECLARE @Uniques Table (ObjectID Int);

        DECLARE @Definition Table (DefinitionID SmallInt IDENTITY(1, 1), FieldValue Varchar(2000));

        SET @sql = N'
  use ' + @DBName + N'
  SELECT distinct DB_NAME()
            ,TABLE_SCHEMA
            ,TABLE_NAME
            ,''[''+COLUMN_NAME+'']'' as COLUMN_NAME
            ,CAST(ORDINAL_POSITION AS INT)
            ,COLUMN_DEFAULT
            ,dobj.name AS ColumnDefaultName
            ,CASE WHEN c.IS_NULLABLE = ''YES'' THEN 1 ELSE 0 END
            ,DATA_TYPE
            ,case CHARACTER_MAXIMUM_LENGTH when -1 then ''max'' else CAST(CHARACTER_MAXIMUM_LENGTH AS varchar) end--CAST(CHARACTER_MAXIMUM_LENGTH AS INT)
            ,CAST(NUMERIC_PRECISION AS INT)
            ,CAST(NUMERIC_SCALE AS INT)
            ,DOMAIN_NAME
            ,COLUMN_NAME + '',''
            ,'''' AS FieldDefinition
            ,CASE WHEN ic.object_id IS NULL THEN 0 ELSE 1 END AS IdentityColumn
            ,CAST(ISNULL(ic.seed_value,0) AS INT) AS IdentitySeed
            ,CAST(ISNULL(ic.increment_value,0) AS INT) AS IdentityIncrement
            ,CASE WHEN st.collation_name IS NOT NULL THEN 1 ELSE 0 END AS IsCharColumn 
            ,cc.definition 
            FROM INFORMATION_SCHEMA.COLUMNS c
            JOIN sys.columns sc ON  c.TABLE_NAME = OBJECT_NAME(sc.object_id) AND c.COLUMN_NAME = sc.Name
            LEFT JOIN sys.identity_columns ic ON c.TABLE_NAME = OBJECT_NAME(ic.object_id) AND c.COLUMN_NAME = ic.Name
            JOIN sys.types st ON COALESCE(c.DOMAIN_NAME,c.DATA_TYPE) = st.name
            LEFT OUTER JOIN sys.objects dobj ON dobj.object_id = sc.default_object_id AND dobj.type = ''D''
            left join sys.computed_columns cc on c.TABLE_NAME=OBJECT_NAME(cc.object_id) and sc.column_id=cc.column_id
    WHERE c.TABLE_NAME = @TableName and c.TABLE_SCHEMA=@schema 
    ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION
    '   ;

        --PRINT @sql;
        INSERT INTO @ShowFields (DatabaseName
                               , TableOwner
                               , TableName
                               , FieldName
                               , ColumnPosition
                               , ColumnDefaultValue
                               , ColumnDefaultName
                               , IsNullable
                               , DataType
                               , MaxLength
                               , NumericPrecision
                               , NumericScale
                               , DomainName
                               , FieldListingName
                               , FieldDefinition
                               , IdentityColumn
                               , IdentitySeed
                               , IdentityIncrement
                               , IsCharColumn
                               , IsComputed)
        EXEC sys.sp_executesql @sql
                             , N'@TableName varchar(50),@schema varchar(50)'
                             , @TableName = @TableName
                             , @schema = @schema;

        SELECT TOP 1 @TableSchema = TableOwner FROM @ShowFields;

        INSERT INTO @HoldingArea (Flds) VALUES ('(');

        IF @includeTable = 1
            BEGIN
                INSERT INTO @Definition (FieldValue)
                VALUES
                (   'CREATE TABLE ' + CASE
                                          WHEN @NewTableName IS NOT NULL THEN
                                              @DBName + '.' + @NewTableSchema + '.' + @NewTableName
                                          ELSE
                                              @DBName + '.' + @TableSchema + '.' + @TableName
                                      END);

                INSERT INTO @Definition (FieldValue) VALUES ('(');

                INSERT INTO @Definition (FieldValue)
                SELECT Char(10) + FieldName + ' '
                       + CASE
                             WHEN DomainName IS NOT NULL AND @UseSystemDataTypes = 0 THEN
                                 DomainName + CASE WHEN IsNullable = 1 THEN ' NULL ' ELSE ' NOT NULL ' END
                             ELSE
                                 CASE
                                     WHEN IsComputed IS NULL THEN
                                         Upper(DataType)
                                         + CASE
                                               WHEN IsCharColumn = 1 THEN
                                                   '(' + Cast(MaxLength AS Varchar(10)) + ')'
                                               ELSE
                                                   CASE
                                                       WHEN DataType = 'numeric' THEN
                                                           '(' + Cast(NumericPrecision AS Varchar(10)) + ','
                                                           + Cast(NumericScale AS Varchar(10)) + ')'
                                                       ELSE
                                                           CASE
                                                               WHEN DataType = 'decimal' THEN
                                                                   '(' + Cast(NumericPrecision AS Varchar(10)) + ','
                                                                   + Cast(NumericScale AS Varchar(10)) + ')'
                                                               ELSE
                                                                   ''
                                                           END
                                                   END
                                           END
                                         + CASE
                                               WHEN IdentityColumn = 1 THEN
                                                   ' IDENTITY(' + Cast(IdentitySeed AS Varchar(5)) + ','
                                                   + Cast(IdentityIncrement AS Varchar(5)) + ')'
                                               ELSE
                                                   ''
                                           END + CASE WHEN IsNullable = 1 THEN ' NULL ' ELSE ' NOT NULL ' END
                                         + CASE
                                               WHEN ColumnDefaultName IS NOT NULL AND @IncludeConstraints = 1 THEN
                                                   'CONSTRAINT ['
                                                   + Replace(ColumnDefaultName, @TableName, @NewTableName)
                                                   + '] DEFAULT' + Upper(ColumnDefaultValue)
                                               ELSE
                                                   ''
                                           END
                                     ELSE
                                         ' as ' + IsComputed + ' '
                                 END
                         END + CASE
                                   WHEN FieldID = (SELECT Max(FieldID)FROM @ShowFields) THEN
                                       ''
                                   ELSE
                                       ','
                               END
                FROM @ShowFields;

                --------------------------------------------------
                IF @IncludeConstraints = 1
                    BEGIN
                        SET @sql = N'
        use ' +         @DBName + N'
        SELECT  distinct  '',CONSTRAINT ['' + replace(name,@TableName,@NewTableName) + ''] FOREIGN KEY ('' + ParentColumns + '') REFERENCES ['' + ReferencedObject + '']('' + ReferencedColumns + '')'' 
           FROM ( SELECT   ReferencedObject = OBJECT_NAME(fk.referenced_object_id), ParentObject = OBJECT_NAME(parent_object_id),fk.name
                ,   REVERSE(SUBSTRING(REVERSE((   SELECT cp.name + '',''   
                FROM   sys.foreign_key_columns fkc   
                JOIN sys.columns cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id   
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('''')   )), 2, 8000)) ParentColumns,   
                REVERSE(SUBSTRING(REVERSE((   SELECT cr.name + '',''   
                FROM   sys.foreign_key_columns fkc  
                JOIN sys.columns cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id
                WHERE fkc.constraint_object_id = fk.object_id   FOR XML PATH('''')   )), 2, 8000)) ReferencedColumns   
                FROM sys.foreign_keys fk    
                    inner join sys.schemas s on fk.schema_id=s.schema_id and s.name=@schema) a    
            WHERE ParentObject = @TableName    
        '               ;

                        --PRINT @sql;
                        INSERT INTO @Definition (FieldValue)
                        EXEC sys.sp_executesql @sql
                                             , N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50)'
                                             , @TableName = @TableName
                                             , @NewTableName = @NewTableName
                                             , @schema = @schema;

                        SET @sql = N'
            use ' +     @DBName + N'
            SELECT distinct '',CONSTRAINT ['' + replace(c.name,@TableName,@NewTableName) + ''] CHECK '' + definition 
            FROM sys.check_constraints c join sys.schemas s on c.schema_id=s.schema_id and s.name=@schema    
            WHERE OBJECT_NAME(parent_object_id) = @TableName
            '           ;

                        --PRINT @sql;
                        INSERT INTO @Definition (FieldValue)
                        EXEC sys.sp_executesql @sql
                                             , N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50)'
                                             , @TableName = @TableName
                                             , @NewTableName = @NewTableName
                                             , @schema = @schema;

                        SET @sql = N'
            use ' +     @DBName + N'
            SELECT DISTINCT  PKObject = cco.object_id 
            FROM    sys.key_constraints cco    
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id    
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            WHERE    OBJECT_NAME(parent_object_id) = @TableName    AND  i.type = 1 AND    is_primary_key = 1
            '           ;

                        --PRINT @sql;
                        INSERT INTO @PKObjectID (ObjectID)
                        EXEC sys.sp_executesql @sql
                                             , N'@TableName varchar(50),@schema varchar(50)'
                                             , @TableName = @TableName
                                             , @schema = @schema;

                        SET @sql = N'
            use ' +     @DBName + N'
            SELECT DISTINCT    PKObject = cco.object_id
            FROM    sys.key_constraints cco   
            JOIN sys.index_columns cc ON cco.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id  
            JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id
            join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            WHERE    OBJECT_NAME(parent_object_id) = @TableName AND  i.type = 2 AND    is_primary_key = 0 AND    is_unique_constraint = 1
            '           ;

                        --PRINT @sql;
                        INSERT INTO @Uniques (ObjectID)
                        EXEC sys.sp_executesql @sql
                                             , N'@TableName varchar(50),@schema varchar(50)'
                                             , @TableName = @TableName
                                             , @schema = @schema;

                        SET @ClusteredPK = CASE WHEN @@ROWCOUNT > 0 THEN 1 ELSE 0 END;

                        DECLARE @t TestTableType;

                        INSERT @t SELECT * FROM @PKObjectID;

                        DECLARE @u TestTableType;

                        INSERT @u SELECT * FROM @Uniques;

                        SET @sql = N'
            use ' +     @DBName + N'
            SELECT distinct '',CONSTRAINT '' + replace(cco.name,@TableName,@NewTableName) + CASE type WHEN ''PK'' THEN '' PRIMARY KEY '' + CASE WHEN pk.ObjectID IS NULL THEN '' NONCLUSTERED '' ELSE '' CLUSTERED '' END  WHEN ''UQ'' THEN '' UNIQUE '' END + CASE WHEN u.ObjectID IS NOT NULL THEN '' NONCLUSTERED '' ELSE '''' END 
            + ''(''+REVERSE(SUBSTRING(REVERSE(( SELECT   c.name +  + CASE WHEN cc.is_descending_key = 1 THEN '' DESC'' ELSE '' ASC'' END + '',''    
            FROM   sys.key_constraints ccok   
            LEFT JOIN sys.index_columns cc ON ccok.parent_object_id = cc.object_id AND cco.unique_index_id = cc.index_id
            LEFT JOIN sys.columns c ON cc.object_id = c.object_id AND cc.column_id = c.column_id 
            LEFT JOIN sys.indexes i ON cc.object_id = i.object_id AND cc.index_id = i.index_id  
            WHERE i.object_id = ccok.parent_object_id AND   ccok.object_id = cco.object_id    
            order by key_ordinal FOR XML PATH(''''))), 2, 8000)) + '')''
            FROM sys.key_constraints cco 
            inner join sys.schemas s on cco.schema_id=s.schema_id and s.name=@schema
            LEFT JOIN @U u ON cco.object_id = u.objectID
            LEFT JOIN @t pk ON cco.object_id = pk.ObjectID    
            WHERE    OBJECT_NAME(cco.parent_object_id) = @TableName 

            '           ;

                        --PRINT @sql;
                        INSERT INTO @Definition (FieldValue)
                        EXEC sys.sp_executesql @sql
                                             , N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50),@t TestTableType readonly,@u TestTableType readonly'
                                             , @TableName = @TableName
                                             , @NewTableName = @NewTableName
                                             , @schema = @schema
                                             , @t = @t
                                             , @u = @u;
                    END;

                INSERT INTO @Definition (FieldValue) VALUES (')');
            END;

        SET @sql = N'
        use ' + @DBName
                   + N'
        select '' on '' + d.name + ''([''+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)
                          join sys.schemas s on t.schema_id=s.schema_id
                          join sys.data_spaces d on i.data_space_id=d.data_space_id
        where t.name=@TableName and s.name=@schema
        order by key_ordinal
        ';

        PRINT 'x';

        --PRINT @sql;
        INSERT INTO @Definition (FieldValue)
        EXEC sys.sp_executesql @sql
                             , N'@TableName varchar(50),@schema varchar(50)'
                             , @TableName = @TableName
                             , @schema = @schema;

        IF @IncludeClusteredIndex = 1
            BEGIN
                SET @sql = N'
            use ' + @DBName
                           + N'
            SELECT distinct '' CREATE '' + CASE WHEN i.is_unique = 1 THEN ''UNIQUE '' ELSE '''' end + i.type_desc + '' INDEX ['' + replace(i.name COLLATE SQL_Latin1_General_CP1_CI_AS,@TableName,@NewTableName) + ''] ON '
                           + @DBName + N'.' + @NewTableSchema + N'.' + @NewTableName
                           + N' ('' 
            +   REVERSE(SUBSTRING(REVERSE((   SELECT name + CASE WHEN sc.is_descending_key = 1 THEN '' DESC'' ELSE '' ASC'' END + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=0
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000)) + '')''+
            ISNULL( '' include (''+REVERSE(SUBSTRING(REVERSE((   SELECT name + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=1 
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000))+'')'' ,'''')+''''    
            FROM sys.indexes i join sys.tables t on i.object_id=t.object_id
                               join sys.schemas s on t.schema_id=s.schema_id   
            AND CASE WHEN @ClusteredPK = 1 AND is_primary_key = 1 AND i.type = 1 THEN 0 ELSE 1 END = 1   AND is_unique_constraint = 0   AND is_primary_key = 0 
                where t.name=@TableName and s.name=@schema and i.type_desc = ''CLUSTERED''
            '   ;

                --PRINT @sql;
                INSERT INTO @Definition (FieldValue)
                EXEC sys.sp_executesql @sql
                                     , N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50), @ClusteredPK bit'
                                     , @TableName = @TableName
                                     , @NewTableName = @NewTableName
                                     , @schema = @schema
                                     , @ClusteredPK = @ClusteredPK;
            END;

        IF @IncludeIndexes = 1
            BEGIN
                SET @sql = N'
            use ' + @DBName
                           + N'
            SELECT distinct '' CREATE '' + CASE WHEN i.is_unique = 1 THEN ''UNIQUE '' ELSE '''' end + i.type_desc + '' INDEX ['' + replace(i.name COLLATE SQL_Latin1_General_CP1_CI_AS,@TableName,@NewTableName) + ''] ON '
                           + @DBName + N'.' + @NewTableSchema + N'.' + @NewTableName
                           + N' ('' 
            +   REVERSE(SUBSTRING(REVERSE((   SELECT name + CASE WHEN sc.is_descending_key = 1 THEN '' DESC'' ELSE '' ASC'' END + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=0
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000)) + '')''+
            ISNULL( '' include (''+REVERSE(SUBSTRING(REVERSE((   SELECT name + '',''   
            FROM  sys.index_columns sc  
            JOIN sys.columns c ON sc.object_id = c.object_id AND sc.column_id = c.column_id   
            WHERE  t.name=@TableName AND  sc.object_id = i.object_id AND  sc.index_id = i.index_id   
                                         and is_included_column=1 
            ORDER BY key_ordinal ASC   FOR XML PATH('''')    )), 2, 8000))+'')'' ,'''')+''''    
            FROM sys.indexes i join sys.tables t on i.object_id=t.object_id
                               join sys.schemas s on t.schema_id=s.schema_id   
            AND CASE WHEN @ClusteredPK = 1 AND is_primary_key = 1 AND i.type = 1 THEN 0 ELSE 1 END = 1   AND is_unique_constraint = 0   AND is_primary_key = 0 
                where t.name=@TableName and s.name=@schema and i.type_desc <> ''CLUSTERED''
            '   ;

                PRINT @sql;

                INSERT INTO @Definition (FieldValue)
                EXEC sys.sp_executesql @sql
                                     , N'@TableName varchar(50),@NewTableName varchar(50),@schema varchar(50), @ClusteredPK bit'
                                     , @TableName = @TableName
                                     , @NewTableName = @NewTableName
                                     , @schema = @schema
                                     , @ClusteredPK = @ClusteredPK;
            END;

        --SELECT * FROM @Definition;
        INSERT INTO @MainDefinition (FieldValue)
        SELECT FieldValue FROM @Definition ORDER BY DefinitionID ASC;

        --SELECT * FROM @MainDefinition;

        ----------------------------------
        DECLARE @q Varchar(MAX);

        SET @q = (SELECT Replace((SELECT FieldValue FROM @MainDefinition FOR XML PATH('')), '</FieldValue>', ''));
        SET @script = (SELECT Replace(@q, '<FieldValue>', ''));
    END TRY
    -- ##############################################################################################################################################################################
    BEGIN CATCH
        BEGIN
            -- INIZIO  Procedura in errore =========================================================================================================================================================
            PRINT '***********************************************************************************************************************************************************';
            PRINT 'ErrorNumber               : ' + Cast(Error_Number() AS NVarchar(MAX));
            PRINT 'ErrorSeverity             : ' + Cast(Error_Severity() AS NVarchar(MAX));
            PRINT 'ErrorState                : ' + Cast(Error_State() AS NVarchar(MAX));
            PRINT 'ErrorLine                 : ' + Cast(Error_Line() AS NVarchar(MAX));
            PRINT 'ErrorMessage              : ' + Cast(Error_Message() AS NVarchar(MAX));
            PRINT '***********************************************************************************************************************************************************';
        -- FINE  Procedura in errore =========================================================================================================================================================
        END;

        SET @script = '';

        RETURN -1;
    END CATCH;
-- ##############################################################################################################################################################################   

-1

Bạn có thể sử dụng tập lệnh này để sao chép cấu trúc bảng có khóa ngoại nhưng không có chỉ mục. Kịch bản lệnh này xử lý các loại do người dùng xác định và các cột được tính toán một cách duyên dáng.

--\
---) Author: Hans Michiels
---) Script to copy a sql server table structure with foreign keys but without indexes.
---) This script handles user defined types and computed columns gracefully.
--/
/*
(c) Copyright 2016 - hansmichiels.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

--\
---) VARIABLES DECLARATIONS
--/
DECLARE @CrLf NVARCHAR(2) 
DECLARE @Indent NVARCHAR(2) 
DECLARE @nsql NVARCHAR(MAX)
DECLARE @SimulationMode CHAR(1) 
DECLARE @SourceSchemaAndTable NVARCHAR(260) 
DECLARE @TargetSchemaAndTable NVARCHAR(260) 
DECLARE @FkNameSuffix NVARCHAR(128)
DECLARE @TableOptions NVARCHAR(500)

--\
---) CONFIGURATION: set the source and target schema/tablename here, and some other settings.
--/
SELECT 
    @SimulationMode = 'Y' -- Use Y if you only want the SQL statement in the output window without it being executed.
  , @SourceSchemaAndTable = '[Production].[Product]'
  , @TargetSchemaAndTable = '[stg].[Product]'
  , @TableOptions = ' WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]'
  , @FkNameSuffix = '_' + REPLACE(CAST(NEWID() AS VARCHAR(40)), '-', '') -- A Guid is added to the foreign key name to make it unique.
  , @CrLf = CHAR(13) + CHAR(10)
  , @Indent = SPACE(2)
  -- For 'min' script use this (in case sql is near 4000 characters):
  -- , @CrLf  = ' '
  -- , @Indent = ''

--\
---) BUILD SQL FOR CLONING TABLE
--/
SELECT @nsql
    = ISNULL(@nsql, '')
    + CASE col_sequence WHEN 1 THEN
      @CrLf + 'IF OBJECT_ID(N''' + @TargetSchemaAndTable + ''', ''U'') IS NOT NULL DROP TABLE ' + @TargetSchemaAndTable + ';'
    + @CrLf + 'CREATE TABLE ' + @TargetSchemaAndTable + @CrLf + @Indent + '( ' ELSE @CrLf + @Indent + ', ' END
    + [definition]
FROM (
      SELECT ROW_NUMBER() OVER (PARTITION BY tb.object_id ORDER BY tb.object_id, col.column_id) AS col_sequence
        , QUOTENAME(col.name) + ' '
        + COALESCE(
            'AS ' + cmp.definition + CASE ISNULL(cmp.is_persisted, 0) WHEN 1 THEN ' PERSISTED ' ELSE '' END,
            CASE
              WHEN col.system_type_id != col.user_type_id THEN QUOTENAME(usr_tp.schema_name) + '.' + QUOTENAME(usr_tp.name)
              ELSE
                QUOTENAME(sys_tp.name) +
                CASE
                  WHEN sys_tp.name IN ('char', 'varchar', 'binary', 'varbinary') THEN '(' + CONVERT(VARCHAR, CASE col.max_length WHEN -1 THEN 'max' ELSE CAST(col.max_length AS varchar(10)) END) + ')'
                  WHEN sys_tp.name IN ('nchar', 'nvarchar') THEN '(' + CONVERT(VARCHAR, CASE col.max_length WHEN -1 THEN 'max' ELSE CAST(col.max_length/2 AS varchar(10)) END) + ')'
                  WHEN sys_tp.name IN ('decimal', 'numeric') THEN '(' + CAST(col.precision AS VARCHAR) + ',' + CAST(col.scale AS VARCHAR) +  ')'
                  WHEN sys_tp.name IN ('datetime2') THEN '(' + CAST(col.scale AS VARCHAR) +  ')'
                  ELSE ''
                END          
            END
            )       
        + CASE col.is_nullable
            WHEN 0 THEN ' NOT'
            ELSE ''
          END + ' NULL' AS [definition]
        FROM sys.tables tb
        JOIN sys.schemas sch
          ON sch.schema_id = tb.schema_id
        JOIN sys.columns col
          ON col.object_id = tb.object_id
        JOIN sys.types sys_tp
          ON col.system_type_id = sys_tp.system_type_id
        AND col.system_type_id = sys_tp.user_type_id
        LEFT JOIN
            (
            SELECT tp.*, sch.name AS [schema_name]
            FROM sys.types tp
            JOIN sys.schemas sch
            ON tp.schema_id = sch.schema_id
            ) usr_tp
          ON col.system_type_id = usr_tp.system_type_id
        AND col.user_type_id = usr_tp.user_type_id
        LEFT JOIN sys.computed_columns cmp
          ON cmp.object_id = tb.object_id
        AND cmp.column_id = col.column_id
      WHERE tb.object_id = OBJECT_ID(@SourceSchemaAndTable, 'U')
      ) subqry
;
SELECT @nsql
    = ISNULL(@nsql, '')
    + CASE col_sequence
        WHEN 1 THEN @CrLf + ', PRIMARY KEY ' + CASE is_clustered_index WHEN 1 THEN 'CLUSTERED' ELSE 'NONCLUSTERED' END
            + @CrLf + @Indent + '( '
        ELSE @CrLf + @Indent + ', '
      END
    + QUOTENAME(pk_cols.column_name)
    + CASE is_descending_key
        WHEN 1 THEN ' DESC'
        ELSE ' ASC'
      END
FROM (
      SELECT TOP 2147483647 sch.name as schema_name, tb.name as table_name, col.name as column_name
                , ROW_NUMBER() OVER (PARTITION BY tb.object_id ORDER BY tb.object_id, col.column_id) AS col_sequence
                , ic.is_descending_key
                , CASE WHEN idx.index_id = 1 THEN 1 ELSE 0 END AS [is_clustered_index]
        FROM sys.tables tb
        JOIN sys.schemas sch
          ON sch.schema_id = tb.schema_id
        JOIN sys.indexes idx
          ON idx.is_primary_key = 1
        AND idx.object_id = tb.object_id
        JOIN sys.index_columns ic
          ON is_included_column = 0  
        AND ic.object_id = tb.object_id
        AND ic.index_id = idx.index_id
        JOIN sys.columns col
          ON col.column_id = ic.column_id
        AND col.object_id = tb.object_id
      WHERE tb.object_id = OBJECT_ID(@SourceSchemaAndTable, 'U')
      ORDER BY col.column_id
      ) pk_cols

SELECT @nsql = @nsql + @CrLf + @indent + ') ' + @TableOptions

IF @SimulationMode = 'Y' 
BEGIN
  PRINT '-- Simulation mode: script is not executed.'
END
PRINT @nsql;
IF @SimulationMode != 'Y' 
BEGIN
  EXEC(@nsql);
END

--\
---) Copy foreign key constraints
---) A guid is added to the foreign key name to make it unique within the database.
--/
SET @nsql = N'';
SELECT @nsql += N'
ALTER TABLE '
      + @TargetSchemaAndTable
      + ' ADD CONSTRAINT [' + LEFT(fk.name + @FkNameSuffix, 128) +  '] '
      + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(col.name)
      -- get all the columns in the constraint table
      FROM sys.columns AS col
      JOIN sys.foreign_key_columns AS fkc
        ON fkc.parent_column_id = col.column_id
        AND fkc.parent_object_id = col.[object_id]
      WHERE fkc.constraint_object_id = fk.[object_id]
      ORDER BY fkc.constraint_column_id
      FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
      + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rtb.name)
      + '('
      + STUFF((SELECT ',' + QUOTENAME(col.name)
      -- get all the referenced columns
      FROM sys.columns AS col
      JOIN sys.foreign_key_columns AS fkc
        ON fkc.referenced_column_id = col.column_id
        AND fkc.referenced_object_id = col.[object_id]
      WHERE fkc.constraint_object_id = fk.object_id
      ORDER BY fkc.constraint_column_id
      FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');'
FROM sys.foreign_keys AS fk
JOIN sys.tables AS rtb -- referenced table
    ON fk.referenced_object_id = rtb.[object_id]
JOIN sys.schemas AS rs
    ON rtb.[schema_id] = rs.[schema_id]
JOIN sys.tables AS ctb -- constraint table
    ON fk.parent_object_id = ctb.[object_id]
WHERE rtb.is_ms_shipped = 0 AND ctb.is_ms_shipped = 0
  AND ctb.object_id = OBJECT_ID(@SourceSchemaAndTable, 'U');

IF @SimulationMode = 'Y' 
BEGIN
  PRINT '-- Simulation mode: script is not executed.'
END
PRINT @nsql;
IF @SimulationMode != 'Y' 
BEGIN
  EXEC(@nsql);
END

Nếu bạn quan tâm, bạn cũng có thể tìm thấy nó trên blog của tôi: http://www.hansmichiels.com/2016/02/18/how-to-copy-a-database-table-structure-t-sql-scripting-series -s01e01 /


-2
Select *
into [new table name]
from [table to be copied name]
where 0=1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.