Data reload from PROD to Non-PROD in sequence of table referenced by Foreign Key [closed]

  Kiến thức lập trình

Is there any dynamic script that will

  1. Truncate multiple tables in sequence
  2. Load data from another server using Linked Server,
  3. Take care of the reload sequence so there should not be any Foreign Key reference errors,
    Ideal sequence:
    a) Drop FKs,
    b) truncate tables,
    c) Reload data,
    (i) Set Identity Insert on
    (ii) insert data
    (iii) Set Identity Insert off
    d) Create the foreign key
  4. Capable of identifying the database tables, constraints, and keys without taking it as input from the user.

1

Recently I’ve generated the following script which helped me reload (retrofit) data from production to non-production environment:

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

LEAVE A COMMENT