按照外键引用的表的顺序将数据从 PROD 重新加载到非 PROD [已关闭]

问题描述 投票:0回答:1

有没有动态脚本可以

  1. 按顺序截断多个表
  2. 使用链接服务器从另一台服务器加载数据,
  3. 注意重新加载顺序,以免出现任何外键引用错误, 理想的顺序: a) 删除 FK, b) 截断表, c) 重新加载数据,
    (i) 将身份插入设置为 (二) 插入数据 (iii) 将身份插入设置为关闭
    d) 创建外键
  4. 能够识别数据库表、约束和键,而无需将其作为用户的输入。
sql-server
1个回答
-1
投票

最近我生成了以下脚本,它帮助我将数据从生产环境重新加载(改造)到非生产环境:

DECLARE @LinkedServerName NVARCHAR(255) = 'ProductionLinkedServer'
DECLARE @DatabaseName NVARCHAR(255) = 'MyDatabase'
DECLARE @Schema NVARCHAR(255) = 'dbo'

DECLARE @DropForeignKeyTemplate NVARCHAR(MAX) = 'ALTER TABLE %s DROP CONSTRAINT %s;';
DECLARE @CreateForeignKeyTemplate NVARCHAR(MAX) = 'ALTER TABLE %s WITH CHECK ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);';
DECLARE @TruncateTemplate NVARCHAR(MAX) = 'TRUNCATE TABLE %s;';
DECLARE @InsertDataTemplate NVARCHAR(MAX) = 'SET IDENTITY_INSERT %s ON; INSERT INTO %s SELECT * FROM %s.%s.%s.%s; SET IDENTITY_INSERT %s OFF;';

DECLARE @Tables TABLE (
    TableName NVARCHAR(MAX),
    ForeignKeyTableName NVARCHAR(MAX),
    ForeignKeyConstraintName NVARCHAR(MAX),
    DropForeignKeyScript NVARCHAR(MAX),
    CreateForeignKeyScript NVARCHAR(MAX),
    TruncateScript NVARCHAR(MAX),
    HasForeignKey BIT,
    InsertDataScript NVARCHAR(MAX)
);

INSERT INTO @Tables (TableName, ForeignKeyTableName, ForeignKeyConstraintName, DropForeignKeyScript, CreateForeignKeyScript, TruncateScript, HasForeignKey, InsertDataScript)
SELECT t.name AS TableName,
       OBJECT_NAME(fk.referenced_object_id) AS ForeignKeyTableName,
       fk.name AS ForeignKeyConstraintName,
       IIF(fk.name is not null, FORMATMESSAGE(@DropForeignKeyTemplate, QUOTENAME(t.name),QUOTENAME(fk.name)),'') AS DropForeignKeyScript,
       IIF(fk.name IS NOT NULL, 
          FORMATMESSAGE(@CreateForeignKeyTemplate,QUOTENAME(t.name),QUOTENAME(fk.name)
          ,STRING_AGG(QUOTENAME(c.COLUMN_NAME), ', ') WITHIN GROUP (ORDER BY ic.ORDINAL_POSITION)
          ,QUOTENAME(OBJECT_NAME(fk.referenced_object_id)),STRING_AGG(QUOTENAME(c.COLUMN_NAME), ', ') 
          WITHIN GROUP (ORDER BY ic.ORDINAL_POSITION)), 
           ''
          ) AS CreateForeignKeyScript,
       FORMATMESSAGE(@TruncateTemplate, QUOTENAME(t.name)) AS TruncateScript,
       IIF(fk.name IS NOT NULL, 1, 0) AS HasForeignKey,
       FORMATMESSAGE(@InsertDataTemplate, 
                  QUOTENAME(t.name), 
                  QUOTENAME(t.name), 
                  QUOTENAME(@LinkedServerName), 
                  QUOTENAME(@DatabaseName), 
                  QUOTENAME(@Schema), 
                  QUOTENAME(t.name),
                  QUOTENAME(t.name)) AS InsertDataScript
FROM sys.tables t
LEFT JOIN sys.foreign_keys fk ON fk.parent_object_id = t.object_id
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS ic ON fk.name = ic.CONSTRAINT_NAME
LEFT JOIN INFORMATION_SCHEMA.COLUMNS AS c ON ic.TABLE_NAME = c.TABLE_NAME AND ic.COLUMN_NAME = c.COLUMN_NAME
WHERE 1=1
GROUP BY t.name, fk.name, fk.referenced_object_id
ORDER BY fk.name DESC, t.name;

--CREATE LINKED SERVER IF NOT ALREADY EXISTS
    -- Check if the linked server already exists
    DECLARE @existingLinkedServer NVARCHAR(255)

    SELECT @existingLinkedServer = name
    FROM sys.servers
    WHERE name = @LinkedServerName

    IF @existingLinkedServer IS NULL
    BEGIN
        EXEC sp_addlinkedserver   
           @server = @LinkedServerName, -- Name of the linked server
           @srvproduct = '',  
           @provider = 'SQLNCLI', -- Provider for SQL Server
           @datasrc = 'serveraddress,port', -- IP address and port of the server
           @provstr = 'UID=userId;PWD=password'; -- SQL Server authentication credentials

        PRINT 'Linked server created successfully.'
    END
    ELSE
    BEGIN
        PRINT 'Linked server already exists.'
    END

--EXECUTE THE SCRIPTS
    DECLARE @SqlCommand NVARCHAR(MAX);
    DECLARE @Commands TABLE (Command NVARCHAR(MAX));

    -- Populate the @Commands table with all commands
    INSERT INTO @Commands (Command)
    SELECT DropForeignKeyScript FROM @Tables where DropForeignKeyScript <> '' GROUP BY DropForeignKeyScript 
    UNION ALL
    SELECT TruncateScript FROM @Tables where TruncateScript <> '' GROUP BY TruncateScript 
    UNION ALL
    SELECT InsertDataScript FROM @Tables where InsertDataScript <> '' GROUP BY InsertDataScript
    UNION ALL
    SELECT CreateForeignKeyScript FROM @Tables where CreateForeignKeyScript <> '' GROUP BY CreateForeignKeyScript 

    -- Initialize loop variables
    DECLARE @RowCount INT = (SELECT COUNT(*) FROM @Commands)
    DECLARE @Counter INT = 1
    
    --SELECT * FROM @COMMANDS
        
    -- Loop through each command and execute it
    WHILE @Counter <= @RowCount
    BEGIN
        SELECT @SqlCommand = Command
        FROM @Commands
        WHERE (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) = @Counter
        -- Execute the command
        EXEC sp_executesql @SqlCommand
        SET @Counter = @Counter + 1
    END
© www.soinside.com 2019 - 2024. All rights reserved.