Assign variable the result of a select statement - sql

How would you assign a variable the result of a SELECT in Sql Server?
Here is my attempt:
CREATE PROCEDURE x
AS
BEGIN
DECLARE #MyVar integer
DECLARE #sql nvarchar(150), #v nvarchar(50)
Set #v = 'mytable'
--SET #sql = 'SELECT INTO ' + #MyVar + 'count(*) FROM ' + #v
SET #sql = 'Set ' + #MyVar + '= SELECT count(*) FROM ' + #v
EXEC sp_executesql #sql
print #MyVar
END
Conversion failed when converting the varchar value 'Set ' to data
type int.
Any recommendation on learning the syntax would be useful too. Thank you!

You can use an OUTPUT parameter to sp_executesql as below.
DECLARE #MyVar INTEGER
DECLARE #sql NVARCHAR(MAX),
#v SYSNAME
SET #v = N'mytable'
SET #sql = N'SELECT #MyVar = count(*) FROM ' + QUOTENAME(#v)
EXEC sp_executesql
#sql,
N'#MyVar INT OUTPUT',
#MyVar = #MyVar OUTPUT
PRINT #MyVar
RE: "Recommendation on learning the syntax" I don't really have one other than books online but you should read The Curse and Blessings of Dynamic SQL to see why QUOTENAME is important.

Related

SQL add a variable to a query

How do I create variables that are specified once and then used in queries later in a script? These variables may be used multiple times in a query, and in multiple queries in a script. I use #x as such a variable in the examples below.
What I want to do is something like:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + #x + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Which returns the error mentioned above. I would like it to achieve the equivalent of:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''test'' as [TestCase]
From mytable'
Exec (#Query)
-- Returns e.g.
-- Name TestCase
-- Alice Test
-- Bob Test
I also note that the following doesn't work and returns the same error as the first:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + 'test' + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Based on the error and since I'm not trying to use the #x as a column name, but just as a variable, I assume I'm using an invalid implementation of a variable.
Since you're not trying to use a variable as a column name, you do not need to use dynamic SQL at all. (Which is a Good Thing(TM) since dynamic SQL should only be used with a great deal of caution due to it being a great attack surface.)
A simple:
declare #x nvarchar(40)
set #x = 'test'
select [Name], #x as TestCase
from mytable
will do.
That being said, if you have a use case for dynamic SQL (again the particular query in question here does not but perhaps an ad-hoc query is being passed in to the procedure), the thing to do would be to pass your variable as a parameter to the query via sp_executesql. This is akin to creating a stored procedure with parameters:
declare #x nvarchar(40)
declare #query nvarchar(1000)
set #x = 'test'
set #query = 'select [Name], #x as TestCase from mytable'
exec sp_executesql #query, N'#x nvarchar(1000)', #x
You were missing quotes. Thats it. Try below code.
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''' + #x + ''' as [TestCase]
From mytable'
Exec (#Query)
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name],'++''''+#x+''''+ ' as [TestCase]
From mytable'
print #query
Output:
Select [Name],'test' as [TestCase]
From mytable

Get SQL result into variable

Here is what I have so far. I want to store the query result into an int variable but I get null so far. After execute, both #query and #countrow are both null. Any suggestion would be great.
SET #query = N'select #countrow=count(*) from ' + #tablename
EXECUTE sp_executesql #query
DECLARE #i INT, #sql NVARCHAR(512), #tablename varchar(200) = 'tbl'
SET #sql = N'SELECT #i = COUNT(*) FROM ' + #tablename
EXEC sp_executesql
#query = #sql,
#params = N'#i INT OUTPUT',
#i = #i OUTPUT
PRINT #i
Take a look at SQL Fiddle
You need to use the OUTPUT keyword, similar to this:
declare #query nvarchar(max)
declare #countrow int
declare #tablename varchar(50)
SET #query = N'select #cnt=count(*) from ' + #tablename
EXECUTE sp_executesql #query, N'#cnt int OUTPUT', #cnt=#countrow OUTPUT
select #countrow as countrow -- to get the result

SQL Linked Server query with Parameters

I need to select value from SQL Linked Server & get it to loacal variable
This is what I've written so far:
DECLARE #SQLQUERY AS VARCHAR(1000)
DECLARE #FINALQUERY AS VARCHAR(1000)
DECLARE #OutVal AS VARCHAR(10)
SET #SQLQUERY = 'SELECT Field1 FROM Table1 WHERE Field2=' + CAST(#var1 AS VARCHAR)
SET #FINALQUERY = 'SELECT #OutVal=Field1 FROM OPENQUERY(LINKEDSERVER,' + '''' + #SQLQUERY + '''' + ')'
EXEC(#finalQuery)
but this is wrong as it does not set the local variable(#OutVal).
Instead of exec, use sp_execute_sql with an output parameter:
exec sp_executesql #FinalQuery, N'#OutVal output', #OutVal = #OutVal out
Since sp_executesql expects nvarchar parameters, be sure to change the definition of #FinalQuery to nvarchar(max).
#OutVal in query string does not recognized as a variable. use a function or return table statement.

Selecting from a table where the name is passed as a variable

I am trying to write a simple stored proc which takes three arguments 'database name one', 'database name two' and 'table name'. The sql will then perform a row count for the defined table in each database and store it.
Working on it piecemeal I have hit the first problem in that you can't do
select * from #tablename
I know you can use dynamic sql with the exec command but this is not ideal as I can't return values.
The following example looks like it should work but doesn't.
declare #tablename as nvarchar(500)
declare #sqlstring as nvarchar(500)
declare #parmdefinition as nvarchar(500)
declare #numrows as bigint
set #tablename = N'dummy_customer'
set #parmdefinition = N'#tablenameIN nvarchar(500), #numrowsOUT as bigint OUTPUT'
select #sqlstring = 'select #numrowsOUT = count(*) from #tablenameIN'
select #sqlstring
exec sp_executesql #sqlstring, #parmdefinition, #tablenameIN = #tablename, #numrowsOUT = #numrows OUTPUT
select #numrows
The error message given is
Msg 1087, Level 16, State 1, Line 1
Must declare the table variable "#tablenameIN".
Currently using SQL Server 2008 SP2.
Edit:
We're doing this because we are doing a migration and the customer wants a report which shows the row count for each table in the source and destination database. As there are many tables being able to use sp_MSForEachTable to call the stored proc seems ideal.
Edit:
The final solution for future reference is
declare #tablename as nvarchar(500)
declare #sqlstring as nvarchar(500)
declare #parmdefinition as nvarchar(500)
declare #numrows as bigint
set #tablename = N'dummy_customers'
set #parmdefinition = N'#tablename nvarchar(500), #numrowsOUT as bigint OUTPUT'
select #sqlstring = 'select #numrowsOUT = count(*) from ' + quotename(#tablename)
exec sp_executesql #sqlstring, #parmdefinition, #tablename = #tablename, #numrowsOUT = #numrows OUTPUT
select #numrows
You'd have to use dynamic sql, and concatenate the table name into the SQL string to then execute via sp_executsql:
select #sqlstring = 'select #numrowsOUT = count(*) from ' + QUOTENAME(#tablename)
EXECUTE sp_executesql ....

Dynamic sql statement to update a variable

my sql statement is something like this below
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
SELECT #OLD_NAV_VALUE = [col1] from TBL_BA where DATE = #id_Date
SET #FINAL = #OLD_NAV_VALUE * 50
But the problem i am haveing here is that the column name in the select statement which is given as [col1] is a dynamic value. So i am trying something like this below.
DECLARE #OLD_NAV_VALUE AS INT
DECLARE #FINAL AS INT
EXEC('SELECT #OLD_NAV_VALUE = [' + #DYNAMIC_COL_NAME + '] from TBL_BA where DATE = ' + #id_Date)
SET #FINAL = #OLD_NAV_VALUE * 50
this gives an error that #OLD_NAV_VALUE has to be declared. So i tried declaring #OLD_NAV_VALUE inside the EXEC statement. But if i do this i am not able to use the same outside the EXEC statement.
Please let me know how to do this.
You can also use the sp_executesql statement with an output parameter:
declare #field nvarchar(50);
set #field = N'FieldToSelect';
declare #sql nvarchar(3000);
declare #parmDefinition nvarchar(500);
SET #parmDefinition = N'#returnValueOUT nvarchar(50) OUTPUT';
set #sql = N'SELECT #ReturnValueOUT = ' + #Field + ' FROM [TableName] WHERE [SomeCondition]'
declare #returnValue nvarchar(50);
EXECUTE sp_executesql #sql, #parmDefinition, #returnValueOut = #returnValue OUTPUT;
SELECT #returnValue
First, I'd suggest that you do a Google on "Erland dynamic SQL" and read his white paper on the subject.
Your design is probably not the best if it requires that you use a dynamic column name like this.
The reason that you can't do what you're trying to do is that everything in the EXEC is entirely in its own scope. If you absolutely have to do it this way though then you could use a table (either a normal table, or a global temporary table) to store the value for use outside of the EXEC.
We've used sp_executesql. Here's another example of a parameterized record count:
DECLARE #sql AS nvarchar(MAX)
SET #sql = N'SELECT #RecordCount = COUNT(*) FROM [{#SchemaName}].[{#TableName}]'
SET #sql = REPLACE(#sql, '{#SchemaName}', #SchemaName)
SET #sql = REPLACE(#sql, '{#TableName}', #TableName)
DECLARE #RecordCount AS int
EXEC sp_executesql
#query = #sql,
#params = N'#RecordCount INT OUTPUT',
#RecordCount = #RecordCount OUTPUT
This worked for me.
I declared a temp table and used it to receive the values from the select statement.
Something like below.
declare #i int
declare #v int
create table #t (val int)
insert into #t
exec ('declare #i int set #i = 0 select #i+1')
select * from #t