7

Trying to tidy up my SQL script with SQLCMD mode and I ran into an issue:

:setvar db_suffix "some_suffix"
:setvar some_db "some_db_$(db_suffix)"
print 'some_db: $(some_db)'

The output of that is:

some_db: some_db_$(db_suffix)

However, what I expected was:

some_db: some_db_some_suffix

Is there a way to have variable interpolation like this?

(Note that T-SQL functions such as CONCAT() won't work since I'll be using the variable as a database name).

  • 2
    SQLCMD mode only makes one pass, so I don't think you can have variables feed variables like that. You'll need to do something externally (PowerShell?) or use a file as an intermediary. See this blog post. – Aaron Bertrand Mar 13 '17 at 22:59
11

Is there a way to have variable interpolation like this?

Kinda sorta, in a way. Just not directly.

You need to keep in mind a few things:

  1. The value that you set a variable to via :setvar is a simple, literal value. You can see this by running just the following two lines:

    :setvar var1 $(var2)
    PRINT '$(var1)';
    

    which returns:

    $(var2)
    

    If SQLCMD / SQLCMD-mode attempted to parse the value portion of :setvar in any way, then it would error on $(var2) not being defined.

  2. Variable substitution is allowed in some other SQLCMD commands.

    This means that you can, for example, execute a shell command while passing a SQLCMD variable to that command line:

    :setvar db_suffix some_suffix
    !! echo :setvar other_db [MyDB_$(db_suffix)] > c:\TEMP\setvar.txt
    

    The two lines above will create / overwrite a file, C:\TEMP\setvar.txt, with the text of ":setvar other_db [MyDB_$(db_suffix)]" where $(db_suffix) is replaced with its value of "some_suffix".

  3. SQLCMD commands in a file / script that is imported via the :r command are processed in a second-pass, allowing for variables set in those external files to be reflected in the main script:

    :setvar db_suffix some_suffix
    !! echo :setvar other_db [MyDB_$(db_suffix)] > c:\TEMP\setvar.txt
    :r C:\TEMP\setvar.txt
    PRINT 'somethin_somethin: $(other_db)';
    

    Returns:

    somethin_somethin: [MyDB_some_suffix]
    
  4. SQLCMD commands are interpreted per-each batch !! So if you want to change the concatenated value, then you need to separate each creating and reading of the temp file, else the value you get will be the last one to be set since all of the !! and :r commands will be processed before the variable values are substituted in, and then the batch can be submitted to SQL Server to process the T-SQL. For example:

    :setvar db_suffix some_suffixes
    
    !! echo :setvar other_db [MyDB_$(db_suffix)] > c:\TEMP\setvar.txt
    :r C:\TEMP\setvar.txt
    PRINT 'somethin_somethin: $(other_db)';
    
    --GO
    
    !! echo :setvar other_db [NotMyDB_$(db_suffix)22] > c:\TEMP\setvar.txt
    :r C:\TEMP\setvar.txt
    PRINT 'somethin_somethin2: $(other_db)'
    

    Will return:

    somethin_somethin: [NotMyDB_some_suffixes22]
    somethin_somethin2: [NotMyDB_some_suffixes22]
    

    BUT, uncomment the --GO and you will get the following:

    somethin_somethin: [MyDB_some_suffixes]
    somethin_somethin2: [NotMyDB_some_suffixes22]
    
  • Genius!!! Upvoted and will accept when I get a chance to test it out. Sounds like exactly what I need... wished MSFT had built this into the design natively though :/ – user193130 Mar 21 '17 at 0:31
  • @user193130 Thanks :). And part of me agrees with you about wanting more robust SQLCMD-mode capabilities, but I can also see it from Microsoft's point of view that it would be just another headache to maintain a full-blown pre-processor for a script that will then get sent to a server to get processed. If you need truly dynamic processing, you can use a templating tool such as "T4" that comes with Visual Studio. That allows you to embed C# or VB.NET into a text file to get processed inline :). It's quite handy, actually. Check out: msdn.microsoft.com/en-us/library/bb126445.aspx – Solomon Rutzky Mar 21 '17 at 1:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.