Retrieve parameter value from parameter name as a string in SQL - sql

I am trying to use some dynamic sql. I have generated over 100 parameters, and to speed things up I am trying to use dynamic sql to only insert values into a table that I have to based off of information retrieved from other tables. I have tried many things like adding a cast etc.
Example of what I mean:
DECLARE #var1 NVARCHAR(MAX)
-- Loop through and add various values
SET #var1 = #var1 + #parameterName
-- The parameter name is retrieved from a table that holds this information
the problem is that when I add the parameter name which would be like "#myFirstParameter" into my final expression so something like this:
DECLARE #finalString NVARCHAR(MAX)
SET #finalString = 'INSERT INTO myTableName ([myFirstParameter]) VALUES (#myFirstParameter)'
EXEC(#finalString)
The "#myFirstParameter" does not get replaced by it's value and I get the following error:
Must declare the scalar variable "#myFirstParameter".
Does anyone know of a way to go from the string name of a parameter to the actual value? I am trying to avoid hardcoding all the values and any work around I have attempted has failed and given me errors which appear to be much worse than what I have stated above.

The first way is to add the parameter's value, instead of its name, to the SQL string:
SET #finalString = 'INSERT INTO myTableName ([myFirstParameter]) VALUES (' +
#myFirstParameter + ')'
This assumes the parameter has a string value. If not, you have to cast it, like cast(#myFirstParameter as varchar(128)).
The second way is to use sp_executesql instead of exec:
exec sp_executesql
N'INSERT INTO myTableName ([myFirstParameter]) VALUES (#myFirstParameter)',
N'#myFirstParameter varchar(128)',
#myFirstParameter = #myFirstParameter;

Related

query inside the variable

Is it possible in SQL to use a variable to store query.
For example to save time when subquery is used multiple times inside the main query.
Example:
DECLARE #my_query as varchar(250) = select x from my_table where my_table = y.your_table
SELECT
a,b,c,(#my_query),d,e,f
FROM my_table_1
Is it possible in SQL to use a variable to store query.
Depend on your definition of "query". If you mean store the text which we use to execute the command, then the answer is YES. If you mean an object type query, then the answer is not - since there is no data type that fit this.
What I mean is that a variable can store a value which is string. The string can be any query command that you want. Therefore, you can store for example the text "select col1,col2 from table1".
Next you need to ask how can we use this text in order to execute it as part of a query, which is done using dynamic query.
We can execute a text of a query using the build-in stored procedure sp_executesql, which is build for such needs.
For example:
-- DECLARE VARIABLE
DECLARE #MyQuery NVARCHAR(MAX)
-- SET the value of the variable
SET #MyQuery = 'SELECT ''Yes I can'''
-- Executing a dynamic query
EXECUTE sp_executesql #MyQuery
Here is another example which look more close to your question:
-- First let's create a table
CREATE TABLE T(ID INT)
INSERT T(ID) VALUES (1),(2)
GO
-- And here is what you sked about:
-- DECLARE VARIABLE
DECLARE #MyQuery NVARCHAR(MAX)
-- SET the value of the variable
SET #MyQuery = 'select ID from T where ID = ''1'''
-- Let's combine the text to a full query now
DECLARE #FullQuery NVARCHAR(MAX)
SET #FullQuery = '
SELECT
ID,(' + #MyQuery + ')
FROM T
'
PRINT #FullQuery
-- Executing a dynamic query
EXECUTE sp_executesql #FullQuery
NOTE! Your specific sample of query will return error, which is not related to the question "Is it possible in SQL to use a variable to store query". This is a result of the "query" is not well formatted.
Important! It is HIGHLY recommended to read the document about this stored procedure and learn a bit more of the options it provides us.
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql?view=sql-server-ver15

Rounding a decimal value with dynamic variable

I need to round a value of a column in table A based on another column in table B in a SQL function.
DECLARE #currencyround INT
SELECT #currencyround = ISNULL(currencyround, 2)
FROM dbo.PRTL_currencySettings
When I put value of #currencyround directly in the query like the following, it's working fine:
SELECT
CAST(POS.BALANCE AS DECIMAL(18, 2)) AS DBAmount
FROM
dbo.POS_SALES POS
When I put value of #currencyround like the following, it's showing error:
Incorrect syntax near '#currencyround'.
SELECT
CAST(POS.BALANCE AS DECIMAL(18, #currencyround)) AS DBAmount
FROM
dbo.POS_SALES POS
If you need specific metadata you could use dynamic SQL:
DECLARE #currencyround int;
SELECT #currencyround=ISNULL(currencyround,2) FROM dbo.PRTL_currencySettings;
DECLARE #sql NVARCHAR(MAX) =
N'select CAST(POS.BALANCE AS DECIMAL(18,<currencyround>)) AS DBAmount
FROM dbo.POS_SALES POS';
SET #sql = REPLACE(#sql, '<currencyround>', #currencyround);
EXEC(#sql);
But personally I would not write such code. I would rather format the number in the application layer.
What do you not understand? Type definitions don't allow variables. You could do this with dynamic SQL but that seems like overkill.
If you care about what how the variable is output, use str() or format() to create the format that you want.
If you need to round the values, then how about this:
ROUND(POS.BALANCE, #currencyround)

How do i convert variable name to string name?

Assume I have the following SQL snippet in SQL Server 2012:
DECLARE #fname varchar(20), #strVarName varchar(50)
SET #fname = 'cronus'
SET #strVarName = COVERT_VARIABLE_TO_STRING_NAME ( #fname)
--this should return '#fname'. this is not a value conversion this is converting a variable name to a string name
SELECT #strVarName
How do I do this?
SQL Server does not support reflection. You may be able to retrieve column or table names from its catalog views but with variables you're out of luck. Maybe you'll find another way to solve this issue with dynamic SQL.
Use dynamic sql query
DECLARE #fname varchar(20), #sql varchar(MAX)
SET #fname = 'cronus'
SET #sql = 'SELECT ' + #fname
EXEC (#sql)
There are following Character data types used to store character strings:
char,
varchar,
nvarchar,
text,
If u already used variable as String then why need to convert as a string
DECLARE #fname varchar(20), #strVarName varchar(50)
SET #fname = 'cronus'
SET #strVarName = #fname
SELECT #strVarName
if needed use CAST and CONVERT function
This is such a bizarre question, sounds like something I'd try to do.
Hmm, SQL is not supposed to do this but I guess, it doesn't mean you can't make it.
I think you would effectively have to write your own process to pull this off, something along the lines of:
Create dbo.sProcInserts stored procedure to insert values into a table:
Takes VariableName, Value and possibly table name to insert into as parameters
Create dbo.sProcExec stored procedure to execute stored procedure:
Before execute, read stored procedure into a variable
Find all variables that are SET (i.e. they have a SET #Var = OR SELECT #Var =)
After each variable set, add to your string a line that calls dbo.sProcInserts with the name of the variable and a select #Variable
Execute your newly written stored procedure
That way you don't have to actually make any modifications to your sProcs and it should catch the flow of variables and their changes through your procedure
However the requirement itself is a bit strange for me, but here is a way that could be a good start point for you:
declare #var1 int
Set #var1= 1
--some code here
declare #var2 nvarchar(max)
set #var2 = 10
--some other code here
declare #var3 bit
print ##VERSION
print 'this is fake #value inside a string'
--$ This is a Hint to help me find the Query that should parsed
declare #sql varbinary(max)
select #sql=sql_handle
from sys.sysprocesses
where spid=56
declare #q nvarchar(max)
select #q= substring(text,1,charindex('$',text)-3) from sys.dm_exec_sql_text(#sql)
Select distinct rtrim(ltrim(substring(Name,1,charindex(' ',Name)))) as Name from(
Select substring(replace(Name,'=',' '),8, Len(Name)) as Name from dbo.SplitString(#q,'declare ')
) as K
where Name like '#[^#]%'
By running the above query you will get the variables name.
Output:
#var1
#var2
#var3
You can find the source code for SplitString function Here
Note: If you are using SQL Server 2016 and your database's compatibility level is equal or greater than 130, you can also use SPLIT_STRING introduced by Microsoft it self. Learn more Here

XML DML Replace with a Function Result

I would like to dynamically replace the value of an XML Element, in selected XML value(s) being retrieved from a table. This replacement needs to be performed by a function that I would like to call. I can't even begin to find any clues to point me in the right direction...
I have the follow code snippet (incomplete) that I believe is the correct structure for using XPath to get to the element I want, and to qualify by XPath which records I am interested in (one or more), from there I have no idea how to take the result of the called function, and ideally place the result in a sql:column:
UPDATE [database].[dbo].[table_with_xml]
SET table_with_xml.modify('replace value of (//PrimaryApplicant/FName/text())[1] with sql:column("")')
FROM [database].[dbo].[table_with_xml] AS [XML_Table]
WHERE [XML_Table].XML_Field.value('(//HeaderData/CountryCode/text())[1]', 'varchar(100)') = '123'
First of all, if you want to update table data from a function, you aren't allowed to do it. You can use a stored proc though. You can send 'replace value of' statement (from you syntax above) to it dynamically and send the value with which you want to replace. Here's some code to demonstrate what I'm trying to say:
Create PROC changeXML
#xmlPath nvarchar(max), -- the statement 'replace value of'
#value nvarchar(max) -- the new value
AS
BEGIN
DECLARE #pathString nvarchar(max), #sql NVARCHAR(MAX);
-- create full statement dynamically
SET #pathString = 'replace value of ('+#xmlPath+'text())[1] with ("'+#value+'")';
SELECT #pathString;
-- create dynamic sql and pass pathstring to it.
SET #sql = 'UPDATE [dbo].[tableWithXmlData] SET a.modify(''#p'')';
-- execute dynamic sql
EXEC sp_executesql #sql, N'#p nvarchar(max)', #p = #pathString
END
Then run proc something like this:
EXEC [dbo].[chnageXML] #xmlPath = N'path to your xml value',
#value = N'new value'

Using Parameter Values In SQL Statement

I am trying to write a database script (SQL Server 2008) which will copy information from database tables on one server to corresponding tables in another database on a different server.
I have read that the correct way to do this is to use a sql statement in a format similar to the following:
INSERT INTO <linked_server>.<database>.<owner>.<table_name> SELECT * FROM <linked_server>.<database>.<owner>.<table_name>
As there will be several tables being copied, I would like to declare variables at the top of the script to allow the user to specify the names of each server and database that are to be used. These could then be used throughout the script. However, I am not sure how to use the variable values in the actual SQL statements. What I want to achieve is something like the following:
DECLARE #SERVER_FROM AS NVARCHAR(50) = 'ServerFrom'
DECLARE #DATABASE_FROM AS NVARCHAR(50) = 'DatabaseTo'
DECLARE #SERVER_TO AS NVARCHAR(50) = 'ServerTo'
DECLARE #DATABASE_TO AS NVARCHAR(50) = 'DatabaseTo'
INSERT INTO #SERVER_TO.#DATABASE_TO.dbo.TableName SELECT * FROM #SERVER_FROM.#DATABASE_FROM.dbo.TableName
...
How should I use the # variables in this code in order for it to work correctly?
Additionally, do you think my method above is correct for what I am trying to achieve and should I be using NVARCHAR(50) as my variable type or something else?
Thanks
There is probably a better way to do this, but what you are probably trying to do in your example is what's called dynamic SQL where you treat the statement as a string and the execute it. This would be section #2 here:
http://www.mssqltips.com/tip.asp?tip=1160
There are some major downsides to dynamic SQL. You see a couple other approaches that might be better in that article.
If you want to execute a dynamically generated query then you have to use sp_ExecuteSQL
HTH
For the nvarchar(50) - you'd be better using sysname. This is a synonym in SQL Server (for nvarchar(128)) and represents the maximum length of an object identifier.
have a look at http://msdn.microsoft.com/en-us/library/ms188001.aspx - sp_executesql takes a parameter that is a string and executes the sql in that string. so you'd need to concatenate #SERVER_FROM and other params with the INSERT INTO part to make the entire sql statement, and then pass to sp_executesql.
nvarchar(50) is fine, unless your server/database names are longer than that :)
You can create the select statement by concatenating all the information together and then use sp_executesql
so:
sp_executesql 'INSERT INTO ' + #SERVER_TO + '.' + #DATABASE_TO +
'.dbo.TableName SELECT * FROM ' + #SERVER_FROM + '.' +
#DATABASE_FROM+'.dbo.TableName'
I like to make templates for dynamic SQL things like this - it's a lot easier to maintain complex statements and also sometimes easier to handle nested quotes - and definitely easier when terms need to be repeated in multiple places (like column lists):
DECLARE #sql AS nvarchar(max);
SET #sql = 'INSERT INTO {#SERVER_TO}.{#DATABASE_TO}.dbo.TableName
SELECT *
FROM {#SERVER_FROM}.{#DATABASE_FROM}.dbo.TableName'
SET #sql = REPLACE(#sql, '{#SERVER_TO}', QUOTENAME(#SERVER_TO))
SET #sql = REPLACE(#sql, '{#DATABASE_TO}', QUOTENAME(#DATABASE_TO))
SET #sql = REPLACE(#sql, '{#SERVER_FROM}', QUOTENAME(#SERVER_FROM))
SET #sql = REPLACE(#sql, '{#DATABASE_FROM}', QUOTENAME(#DATABASE_FROM))
EXEC(#sql)