sql-servert-sqlconcatenationsql-server-2019

How to concatenate T-SQL script with a wildcard and to be more dynamic?


I have bottom T-SQL Script:

USE [master]
RESTORE DATABASE [WH_BEE] FROM  
DISK = N'F:\NH\WH_BEE_20240819_1.bak',  
DISK = N'F:\NH\WH_BEE_20240819_2.bak',  
DISK = N'F:\NH\WH_BEE_20240819_3.bak',  
DISK = N'F:\NH\WH_BEE_20240819_4.bak',  
DISK = N'F:\NH\WH_BEE_20240819_5.bak', 
DISK = N'F:\NH\WH_BEE_20240819_6.bak' WITH  FILE = 1, 
MOVE N'WH_Data1' TO N'F:\data\WH_BEE.MDF',  
MOVE N'WH_Data2' TO N'F:\data\WH_BEE_1.NDF',  
MOVE N'WH_Log' TO N'G:\log\WH_BEE.LDF',  NOUNLOAD,  STATS = 5

What I am trying to do is instead of indicating individual date like '20240819', how do I modify these portions (using a wildcard) so that it is more like:

DISK = N'F:\NM\WH_BEE_' + * + '_1.bak'
DISK = N'F:\NM\WH_BEE_' + * + '_2.bak'
DISK = N'F:\NM\WH_BEE_' + * + '_3.bak'
DISK = N'F:\NM\WH_BEE_' + * + '_4.bak'
DISK = N'F:\NM\WH_BEE_' + * + '_5.bak'
DISK = N'F:\NM\WH_BEE_' + * + '_6.bak'

Also, if possibly having more than just 6 files, can I make this T-SQL more dynamic (instead of having strictly 6, just in case it can go up to 7..)?


Solution

  • You can build it dynamically using STRING_AGG with a parameter to say how many files.

    On SQL 2022 and Azure you can just use GENERATE_SERIES to get multiple rows. Otherwise use a VALUES clause and some cross-joins. There are other options to generate multiple rows from nothing.

    DECLARE @sql nvarchar(max);
    DECLARE @maxInputFiles BIGINT = 6;
    
    WITH L1 AS (
        SELECT *
        FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n)
    ),
    L2 AS (
        SELECT 1 n
        FROM L1 AS a, L1 AS b
    )
    SELECT @sql = N'
    RESTORE DATABASE [WH_BEE]
    FROM ' +
      STRING_AGG(
        CONCAT('
    DISK = N''F:\NH\WH_BEE_',
          CONVERT(nvarchar(10), GETDATE(), 110),
          '_',
          g.value,
          '.bak'''
        ),
        ', '
      ) + N'
    WITH FILE = 1, 
    MOVE N''WH_Data1'' TO N''F:\data\WH_BEE.MDF'',  
    MOVE N''WH_Data2'' TO N''F:\data\WH_BEE_1.NDF'',  
    MOVE N''WH_Log'' TO N''G:\log\WH_BEE.LDF'', STATS = 5;
    '
    FROM (
        SELECT TOP(@maxInputFiles)
          ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS value
        FROM L2
    ) AS g;
    
    PRINT @sql;    -- your friend
    
    EXEC master.sys.sp_executesql @sql;
    

    Honestly you should probably just use Powershell and the DbaTools module. This will automatically get all the correct files and generate the correct statement. For example

    Get-ChildItem "F:\NH\WH_BEE_$(Get-Date -Format "yyyyMMdd")_*.bak" | `
    Restore-DbaDatabase `
        -SqlInstance instanceName `
        -Database DbName `
        -FileMapping @{
           "WH_Data1" = "F:\data\WH_BEE.MDF";
           "WH_Data2" = "F:\data\WH_BEE_1.NDF";
           "WH_Log" = "G:\log\WH_BEE.LDF"
        };