如何在正在运行的多个脚本中通用的T-SQL脚本中声明变量

时间:2017-03-21 12:00:06

标签: sql-server tsql deployment sql-server-2014 sqlcmd

我有一组脚本来执行批量数据导入,我试图将其包含在单个“调用”中。使用SqlCmd模式的脚本。我遇到的问题是每个脚本都包含定义路径或公共对象的同一组声明的变量。当我打电话给'#39;脚本我收到vars已经声明的错误。

如果我从单个脚本中提取声明,Intellisense当然会抱怨它们没有被声明。脚本本身需要独立于“调用”而运行。脚本也是如此,理想情况下我还需要在各个脚本中声明的变量。

谢谢。

实施例: 常见的个人脚本声明和初始设置

DECLARE @path varchar(256),
        @currPeriod varchar(25),
        @pastPeriod varchar(25),
        @period varchar(25),
        @fileName varchar(256),
        @sheet varchar(25),
        @sql varchar(MAX)

SET     @path = 'H:\Scripts\DataImport';
SET     @currPeriod = CONCAT(DATEPART(year,GETDATE()),'-',CONVERT(varchar(2), getdate(), 101));
SET     @pastPeriod =  CONCAT(DATEPART(year,DateAdd(month, -1, Convert(date, GETDATE()))),'-',CONVERT(varchar(2), DateAdd(month, -1, Convert(date, GetDate())), 101));
SET     @period = @pastPeriod;  -- Change to currPeriod or pastPeriod based on import type.
SET     @fileName = 'ReferenceClients-' + @period + '.xlsx';
SET     @sheet = '[Sheet1$]';

SET     @sql = 'INSERT INTO #TempRefClients
                SELECT *
                FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
                                ''Excel 12.0; Database=' + @path + '\' + @period + '\' + @fileName + '; HDR=YES; IMEX=1'',
                                ''SELECT * FROM ' + @sheet + ''')'

调用脚本示例 - 使用SqlCmd模式运行

-- Ref Clients
BEGIN
    PRINT ' ';
    PRINT 'Importing Ref Clients';
    :r "H:\Scripts\DataImport\CurrentMonthScripts\BulkImport-RefClients.sql"
END;

-- Top Clients
BEGIN
    PRINT ' ';
    PRINT 'Importing Top Clients';
    :r "H:\Scripts\DataImport\CurrentMonthScripts\BulkImport-TopClients.sql"
END;

1 个答案:

答案 0 :(得分:3)

你应该能够做到这一点:

  1. 不要在主脚本中声明变量。而是创建一个本地临时表:

    CREATE TABLE #ConfigSettings
    (
      [SomePath]        NVARCHAR(500) NOT NULL,
      [CommonObjectA]   NVARCHAR(128) NOT NULL,
      [SomeMaxValue]    INT
    );
    
    INSERT INTO #ConfigSettings VALUES (N'C:\go\here\for\some\reason\', N'objectName', 55);
    
  2. 在每个包含的脚本中,也需要与主脚本分开运行,在变量名称的末尾声明带有脚本ID的变量,以便它们可以单独存在或与其他脚本的变量:

    DECLARE @SomePath_1       NVARCHAR(500) = N'default_when_run_individually',
            @CommonObjectA_1  NVARCHAR(128) = N'default_value',
            @SomeMaxValue_1   INT = default_value;
    

    另一个脚本会:

    DECLARE @SomePath_2       NVARCHAR(500) = N'default_when_run_individually',
            @CommonObjectA_2  NVARCHAR(128) = N'default_value',
            @SomeMaxValue_2   INT = default_value;
    
  3. 在每个脚本中声明变量后,根据本地临时表中的值设置它们:

    IF (OBJECT_ID(N'tempdb..#ConfigSettings') IS NOT NULL)
    BEGIN
      SELECT @SomePath_1 = cnf.[SomePath],
             @CommonObjectA_1 = cnf.[CommonObjectA],
             @SomeMaxValue_1 = cnf.[SomeMaxValue]
      FROM   #ConfigSettings cnf
    END;
    

    当单独运行每个脚本时,变量将保留其默认值。当它们在主脚本中运行时,本地临时表将存在并将覆盖这些默认值。

    1. 同样,不要在主脚本中声明任何内容,甚至不要在本地临时表中声明保存配置值。

    2. 创建一个包含文件,通过:r读取,设置所有SQLCMD变量:

      :setvar SomePath "C:\go\here\for\some\reason\"
      :setvar CommonObject "objectName"
      :setvar SomeMaxValue 55
      
    3. 在每个脚本的顶部,读入该公共包含文件:

      :r C:\AppConfigStuff\CommonIncludeConfigVariables.sql
      
    4. 在每个包含的脚本中,也需要与主脚本分开运行,在变量名称的末尾声明带有脚本ID的变量,以便它们可以单独存在或与其他脚本的变量,并使用SQLCMD变量作为默认值:

      DECLARE @SomePath_1       NVARCHAR(500) = N'$(SomePath)',
              @CommonObjectA_1  NVARCHAR(128) = N'$(CommonObject)',
              @SomeMaxValue_1   INT = $(SomeMaxValue);
      

      另一个脚本会:

      DECLARE @SomePath_2       NVARCHAR(500) = N'$(SomePath)',
              @CommonObjectA_2  NVARCHAR(128) = N'$(CommonObject)',
              @SomeMaxValue_2   INT = $(SomeMaxValue);
      
    5. 在这两种方法中,在每个单独的脚本中使用唯一的变量名称将消除任何冲突,特别是当您有其他原因不放置" GO"脚本之间的陈述。

      而且,在第二种方法中,如果用SQLCMD变量引用替换所有T-SQL变量引用(例如= $(IntVar)),您甚至可能首先不需要T-SQL变量。或= N'$(StringVar)')。