代码之家  ›  专栏  ›  技术社区  ›  Sergej Andrejev

在VS DBPro中动态读取文件(使用SQLCMD)

  •  0
  • Sergej Andrejev  · 技术社区  · 14 年前

    :r .\Data\Test\Classifiers.CodeType.data.sql
    :r .\Data\Test\Classifiers.Currency.data.sql
    :r .\Data\Test\Classifiers.LOB.data.sql
    

    我想创建一个变量ProjectName,这样我就可以轻松地部署不同的项目数据。像这样的东西(不起作用)

    :setvar ProjectName "Test"
    
    :r .\Data\$(ProjectName)\Classifiers.CodeType.data.sql
    :r .\Data\$(ProjectName)\Classifiers.Currency.data.sql
    :r .\Data\$(ProjectName)\Classifiers.LOB.data.sql
    

    如果我可以读取文件夹中的所有文件而不指定路径,那就更好了。

    1 回复  |  直到 14 年前
        1
  •  0
  •   Sergej Andrejev    14 年前

    我已经发现了如何做到这一点。

    首先,需要启用xp_cmdshell实用程序

    RAISERROR ('Enabling xp_cmdshell utility...', 0, 1) WITH NOWAIT
    EXEC sp_configure 'show advanced options', 1
    RECONFIGURE
    EXEC sp_configure 'xp_cmdshell', 1
    RECONFIGURE
    GO
    

    接下来必须定义一个存储过程来完成所有工作。它的工作原理是将所有文件读入一个临时表,然后运行SQLCMD命令来解析每个找到的*。sql文件

    CREATE PROCEDURE [Builder].[RunScriptsInFolder]
        @scriptsDir varchar(255)
    AS
    
    IF len(@scriptsDir) = 0
        RETURN 0
    
    DECLARE @Message VARCHAR(254)
    SET @Message = 'Loading files in ' + @scriptsDir + ' directory...'
    RAISERROR (@Message, 0, 1) WITH NOWAIT 
    
    DECLARE @FileList Table (FileNumber int identity(1,1), FileName varchar(255), Command varchar(2048))
    DECLARE @OutputTable Table (Output varchar(MAX))
    DECLARE @FileName varchar(255)
    DECLARE @Command varchar(2048) 
    DECLARE @FileNum int
    DECLARE @databaseName varchar(255)
    
    SET @databaseName = db_name()
    
    SET @Command = 'DIR /B /O:-N ' + @scriptsDir + '*.sql'
    INSERT INTO @FileList (FileName) EXEC xp_cmdshell @Command 
    UPDATE @FileList SET Command = 'sqlcmd -d ' + @databaseName + ' -i "' + @scriptsDir + FileName + '"'
    
    WHILE EXISTS(SELECT * FROM @FileList)
    BEGIN
        SELECT TOP(1) @FileNum = FileNumber, @FileName = FileName, @Command = Command FROM @FileList 
    
        SET @FileName = '  :r ' + @FileName
        RAISERROR (@FileName, 0, 1) WITH NOWAIT 
        EXEC xp_cmdshell @Command
    
        DELETE FROM @FileList WHERE FileNumber = @FileNum
    END
    RETURN 0;
    

    现在只需调用此存储过程(需要传递包含SQL文件的文件夹的完整路径。可以从MSBuild属性获取项目的路径)。还请注意,我在RunScriptsInFolder调用的调用周围添加了几行代码。因为您不知道文件夹中的文件是按什么顺序执行的,所以应该在执行之前禁用所有外键检查,并在完成后启用它们

    RAISERROR ('Disabling all constraints...', 0, 1) WITH NOWAIT 
    EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
    
    ---- Run all files specified folder
    BEGIN TRANSACTION
    EXEC [Builder].[RunScriptsInFolder] '$(ProjectDir)Scripts\Post-Deployment\Data\'
    COMMIT TRANSACTION
    
    ---- Enable all constraints
    RAISERROR ('Re-enabling all constraints...', 0, 1) WITH NOWAIT 
    exec sp_msforeachtable @command1="print '?'", @command2='ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'
    

    您可能还想知道为什么$(ProjectDir)变量不适合您。要启用它,请打开*。dbproj文件和文本编辑器,并在末尾添加此代码。

    <PropertyGroup>
      <SetVariables>
        <Variable Name="ProjectDir" Value="$(ProjectDir)" />
      </SetVariables>
    </PropertyGroup>
    

    或者,您可以打开数据库项目属性,查找选项卡变量并添加设置变量ProjectDir=$(ProjectDir)