Dynamic values to SQLCMD variable: Setvar - sql-server

I am working with Visual Studio 2017 Database Project (Dacpac) and I have some SQLCMD variables in Publish file (in xml file) like below-
<SqlCmdVariable Include="ClientDBName">
<Value>Client_1</Value>
</SqlCmdVariable>
And my problem is, we have multiple clients and we are deploying the database changes by dacpac for multiple clients in once. So if I assign the static value for my SQLCMD variable "ClientDBName" like above example, it will take the same value (same db name "Client_1") for all the clients.
And to fix that I am using PreDeployment script. In which I am trying to assign dynamic value or db name to the SQLCMD variable "CleintDBName". Like below-
DECLARE #dbname varchar(50)
SET #dbName = "xyz"
:setvar ClientDBName #dbName
But this is not working. I explored it and found this would not work. Another way I am trying to do is by assign the dbname value via calling the script like below-
:setvar ClientDBName "C:\GetDatabaseName.sql"
But this is also not working.
So can anyone help me out on this, how we can assign dynamic values to SQLCMD variable?

The sqlpackage example command below specifies SQLCMD values with the /Variables: argument. These values are used instead of those in the publish profile.
SqlPackage.exe /Action:Publish /SourceFile:"YourDatabase.dacpac" /TargetDatabaseName:YourDatabaseName /TargetServerName:"." /Variables:"ClientDBName=YourValue"
If your actual need is the published database name, you could use the built-in DatabaseName SQLCMD variable instead of a user-defined SQLCMD variable, which will be the /TargetDatabaseName value.

Related

How to set variable in DBeaver Snowflake connection and call with &{foo}?

I am using DBeaver with a snowflake connection and occasionally need to declare variable for the script. I was wondering how how to declare a variable to use specifically for &{foo} ?
I tried #set, SET, variable declaration but these were not working with the &{foo}.

sqlcmd scripting variables understanding problem

try to run sqlcmd from powershell with some variables.
But get error.
Simple test. I know that this select is really simple but it is sufficient to show the problem.
this is the content of my sql file:
USE [master]
select name from sys.databases where NAME = $(db)
GO
now i run this:
sqlcmd -S testserver -v db="Test" -i \mssql_duplicate\testvariable.sql
i get following message:
Meldung "207", Ebene "16", Status "1", Server "testserver", Zeile 2
"Ungültiger Spaltenname "Test"."
So my question: Why the sqlcmd do this conversion?
When i put he name in the sql script it runs fine:
USE [master]
select name from sys.databases where NAME = "TEST"
GO
sqlcmd -S testserver -i \mssql_duplicate\testvariable.sql
Thanks for your help!
SQLCMD variables can substitute anything, in particular databases' and objects' names. In your example, however, it is used as an ordinary parameter, which is supposed to be of nvarchar(128) data type. So your code should look like this:
USE [master];
select name from sys.databases where NAME = N'$(db)';
GO
Without single quotes, SQL Server interprets your variable as an object name, hence the error.

variable value in file path in execute SQL Task in SSIS?

I am trying to use Execute SQL task in SSIS. but its not accepting variable value in path? The file name is dynamic so, it has to come from variable. The below code is direct input in Execute SQL task.
USE [master]
go
RESTORE DATABASE MyDb FROM
DISK = N'c:\DBRestores\?'
WITH REPLACE
go
then I used, Parameter Mapping to map that value but the task is failing.
Any help? Thanks
You can set dynamic parameter in the Expressions.
In Execute SQL Task Editor, goto Expressions -> Property -> SQLStatementSource -> Expression and put below SQL there, replace your dynamic variable name in it and click on Evaluate Expression and check the Evaluated Value.
"USE [master]
go
RESTORE DATABASE MyDb FROM
DISK = N'c:\\DBRestores\\" + #[User::VariableParameter] + "'
WITH REPLACE
go"
If the evaluated value is as expected, then the script would accept dynamic file names from variable.

Variables declaration in Create Database Script

I have a large database creation query the beginning of which is as follows:
USE Master
GO
IF EXISTS(SELECT * FROM sys.sysdatabases where name = 'MyDatabase')
DROP DATABASE MyDatabase
GO
CREATE DATABASE MyDatabase
GO
USE MyDatabase
GO
I want to declare a variable at the beginning like this:
DECLARE #MainDB VARCHAR(30) = NULL
USE Master
GO
IF EXISTS(SELECT * FROM sys.sysdatabases where name = #MainDB)
DROP DATABASE #MainDB
GO
CREATE DATABASE #MainDB
GO
USE #MainDB
GO
I would execute this query from the command line with the new database name being assigned using the sqlcmd tool. however sql is telling me that the variable #MainDB is not declared. Is this something I can do? If not how would you recommend I work around this problem?
This question is kind of a rehash.
How to use a variable for the database name in T-SQL?
The short answer is you can't have a variable database name. You have to put your T-SQL into a string/VARCHAR(MAX), do a find and replace, then execute it.
Sorry, but you cannot do it like this, because SQL variables only have "batch"-scope and those "GO" commands indicate the boundaries of your batches. Thus, every time you pass GO, all of your variables get wiped out (they're not even Declared any more).
There are several ways around this:
Get Rid of the GO's: This is what we do when we need a Stored Procedure (which cannot have any
GOs in it) instead of a script, but it is a fairly complicated series of sophisticated tricks that have to be wrapped around each other in order to pull it off. You have to be pretty T-SQL adept to use it.
Use a #temp table to hold your values instead. This works because #temp table have session-scope instead or just batch-scope.
I believe that you can also use and manipulate NTDOS environment variables from SQLCMD as well, though I am not familiar with exactly how to do it.
If you want to pursue any of these, let me know which one and I can explain in more detail with examples.
Oops, I missed the "variable Database name" part of this. That can be done as well, but you have to add dynamic SQL to the mix.
You have multiple issues...
GO ends the current batch. So your variable is not visible anymore. You need to move declaration. Also, you cannot DROP DATABASE #MainDB, you have to use dynamic queries. For example,
GO
DECLARE #MainDB VARCHAR(30) = 'MyDB';
IF EXISTS(SELECT * FROM sys.sysdatabases where name = #MainDB)
BEGIN
EXECUTE ('DROP DATABASE '+#MainDB);
END;
You say you need to run this from the command line, so if you have a lot of code which depends on the structure you have already built you can do the following:
Create a temporary copy of the script
Search and replace #MainDB with the DB name you pass in as the parameter in the temporary script
Run the temporary script using the sqlcmd tool
Obviously, remove the DECLARE #MainDB varchar(30) = NULL from your script if you like this option.
If you choose this approach, you can implement your 3 steps using a variety of different technologies (powershell, python, batch file, VBScript ...).
VBScript file approach:
set obj = CreateObject("Scriptlet.TypeLib")
tempsqlfile = obj.GUID & ".sql" 'get a new name for your sql file
set fso = CreateObject("Scripting.FileSystemObject")
set objFile = objFSO.OpenTextFile(tempsqlfile, ForReading) 'open the template file
strSQLText = objFile.ReadAll
objFile.Close
strNewSQLText = Replace(strSQLText, "#MainDB", Wscript.Arguments(1)) 'replace the db name
Set objFile = objFSO.OpenTextFile(tempsqlfile, ForWriting)
objFile.WriteLine strNewText 'write the new file
objFile.Close
Set Shell = WScript.CreateObject("WScript.Shell")
commandLine = "osql -E -i " & Wscript.Arguments(0) & -o " & tempsqlfile & ".rpt"
Set oExec = Shell.Exec(commandLine)
Apologies for the variable names - I cut and pasted bits and pieces from various places but you should get the gist.
(Also - apologies for choosing VBScript out of all those options and be aware that there is no error checking for missing parameters)
As it stands above, if you save that script as 'runmystuff.vbs' then you can do:
runmystuff.vbs sqlfile.sql MagicNewDB
This will replace #MainDB with MagicNewDB everywhere inside the script and then run it using osql.
Found a way to make cmdline variables equal t-sql variables
USE master
GO
DECLARE #Mydb VARCHAR(30) = "$(mydb)"
IF EXISTS(SELECT * FROM sys.sysdatabases where name = #Mydb)
print #Mydb
Execute('create database ' + #Mydb)
The batch file I run from looks like this.
sqlcmd -S %1 -i CreateDatabases.sql -v mydb="%2"
I can now run from sqlcmd and enter my server for %1 and desired DB name for %2.
thanks everyone for the replies they all helped me find the right solution.

How to create object(function) if database name is defined in SQLCMD mode variable?

My SQL looks like this:
:SETVAR VAR_DB_NAME DatabaseName.DBO
SELECT * FROM $(VAR_DB_NAME).tableName
If I try to do:
CREATE FUNCTION $(VAR_DB_NAME).FunctionName
I'm getting an error:
CREATE/ALTER FUNCTION' does not allow specifying the database name as
a prefix to the object name
How can I check if function exists and create/drop it using same variable?
As the error says, you cannot include the database name in the CREATE statement. This works:
:SETVAR VAR_DB_NAME DatabaseName
:SETVAR VAR_SCHEMA_NAME dbo
use $(VAR_DB_NAME)
go
create function $(VAR_SCHEMA_NAME).foo()
returns int
as
begin
return (1)
end
go
It would be better to use two variables here anyway: in my opinion, a variable called "DB_NAME" should not be (mis)used to include a schema name.

Resources