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

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 ....

Related

Dynamic SQL output of a query to a variable

I would like to output the result of the dynamic SQL into a variable called #Count but not sure what the syntax or even the code should like to accomplish this.
The code looks as follows:
declare #tab nvarchar(255) = 'Person.person'
declare #Count int
declare #SQL nvarchar(max) = 'select count(*) from '+ #tab
exec(#SQl)
select #Count
thank you
Here's another way to do it that also safely addresses the SQL Injection isuues:
/* Counts the number of rows from any non-system Table, *SAFELY* */
-- The table name passed
DECLARE #PassedTableName as NVarchar(255) = 'Person.Person';
-- Make sure this isn't a SQL Injection attempt
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = TABLE_SCHEMA + '.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = PARSENAME(#PassedTableName,1)
AND TABLE_SCHEMA = PARSENAME(#PassedTableName,2)
-- make a temp table to hold the results
CREATE TABLE #tmp( cnt INT );
-- create the dynamic SQL
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
-- execute it and store the output into the temp table
INSERT INTO #tmp( cnt )
EXEC(#SQL);
-- Now, finally, we can get it into a local variable
DECLARE #result AS INT;
SELECT #result = cnt FROM #tmp;
You can utilize sp_executesql to execute your count() query, and output it #Count.
Try this:
-- Set the table to count from
declare #tab nvarchar(255) = 'Person.person'
-- Assign the SQL query
declare #SQL nvarchar(255) = N'SELECT count(*) FROM ' + #tab
-- Pepare for sp_executesql
declare #Count int
declare #Params nvarchar(100) = N'#Count int output'
-- Set the count to #Count
exec sp_executesql #SQL, #Params, #Count=#Count output
-- Output #Count
select #Count
One last thing: Person.person looks like you might be trying to reference a person column from a Person table. But the above query is a literal representation of what it looks like you're trying to achieve in your question.
The below question is pretty much identical to what you are asking here.
sp_executeSql with output parameter
DECLARE #retval int
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #tablename nvarchar(50)
SELECT #tablename = N'products'
SELECT #sSQL = N'SELECT #retvalOUT = MAX(ID) FROM ' + #tablename;
SET #ParmDefinition = N'#retvalOUT int OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;

How to set a SQL variable with either EXEC or sp_executesql

I am attempting to build a query on the fly that will set a variable. How would I do this?
Here is what I have so far
DECLARE #SQL as NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
set #SQL = 'set #maxRowCount = (select count(*) from Test)'
SET #ParmDefinition = N'#maxRowCount int';
EXECUTE sp_executesql #SQL, #ParmDefinition
When I run this I get the following error
Msg 8178, Level 16, State 1, Line 1
The parameterized query '(#maxRowCount int)set #maxRowCount = (select count(*) from docto' expects the parameter '#maxRowCount', which was not supplied.
I am trying to get #maxRowCount to be set to the total row count of the Test table
This works, you need the 'OUTPUT' in the parameter definition and a place where the result goes to as well
DECLARE #SQL as NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #iRowCount INT
SET #SQL = 'set #maxRowCount = (select count(*) from Test)'
SET #ParmDefinition = N'#maxRowCount INT OUTPUT';
EXECUTE sp_executesql #SQL, #ParmDefinition, #maxRowCount = #iRowCount OUTPUT
PRINT 'rowcount is:' + CONVERT(VARCHAR,#iRowCount)

Why does storing a value from sp_executesql return NULL?

Once more I stumble upon an SQL mishappening. The following code:
create trigger tc_trigger_olt_UPDATE on tick_orderline_type
for update as
declare #UserId varchar(32) --
declare #ClientId varchar(32) --
declare #CaseId varchar(32) --
declare #TableName varchar(64) --Used
declare #RecordId varchar(512) --Used
declare #Descr varchar(128) --
declare #RemoteIP varchar(16) --Used
select #TableName = object_name(parent_id) from sys.triggers where object_id = ##procid
select #RemoteIP = client_net_address from sys.dm_exec_connections where Session_id = ##SPID
if exists(select * from information_schema.columns where table_name = #TableName and column_name = 'id')
begin
select #RecordId = id from inserted
end
declare #sql nvarchar(max)
set #sql = 'select case_id from '+#TableName+' where id = '''+#RecordId+'''';
exec sp_executesql #sql, N'#out_param varchar(32) OUTPUT', #out_param=#CaseId OUTPUT
execute update_tick_orderline_type #UserId, #ClientId, #CaseId, #TableName, #RecordId, #Descr, #RemoteIP
Is used for filling and audit-table in SSMS, which works. It stores which table, which record, on which date and from which IP-Address the table has been edited.
I am currently trying to get which client's data, for which case, has been edited using the following snipped from above:
declare #sql nvarchar(max)
set #sql = 'select case_id from '+#TableName+' where id = '''+#RecordId+'''';
exec sp_executesql #sql, N'#out_param varchar(32) OUTPUT', #out_param=#CaseId OUTPUT
In my Results window (the one that shows select statement results), I can see that the #sql statement has selected the correct case_id; storing it in the #CaseId variable however, returns NULL. Once I have the #CaseId I can get the #ClientId, so I'm stumped here.
Why is the statement outputting the correct case_id, but stores it as NULL?
A little sidenote: the case_id is only being output when the exec statement is present, otherwise it is not
I managed to fix my own predicament, by changing the previous 'select x from #TableName' block, to this:
declare #sql nvarchar(max)
declare #params nvarchar(max)
set #params = N'#iCaseId varchar(max) output'
select #sql = N'select #iCaseId = case_id from '+quotename(#TableName)+
' where id = '''+#RecordId+''''
execute sp_executesql #sql, #params, #CaseId output
What changed?
I declared an additional #params variable, for readability
Instead of set I select-ed the #sql variable
quotename now surrounds the #TableName variable
instead of the last param for sp_executesql being #x = #y output I simply replaced it with #y output
Conclusion
After several tests (mainly removing some of the changes), I can conclude that the last point on that list was key to solving the issue.
With quotename removed from the statement, I still manage to save the result in a variable, and since the #param variable is not mandatory, but rather a personal preference, it also had no real significance.

sql server save result of exec(#query) in string

I have a query which returns a single result.
#query='select name from studtable where id=1'
How should I write query so that result is saved in string and #result contains result.
#result=exec(#query)
To execute a string, we recommend that you use the sp_executesql stored procedure
instead of the EXECUTE statement. Because this stored procedure supports parameter
substitution, sp_executesql is more versatile than EXECUTE; and because
sp_executesql generates execution plans that are more likely to be reused by SQL
Server, sp_executesql is more efficient than EXECUTE.
Read more here:http://technet.microsoft.com/en-us/library/ms175170(v=sql.105).aspx
So you can write as"
DECLARE #SQLString NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
DECLARE #name varchar(30)
SET #SQLString = N'SELECT #nameOUT = name
from studtable where id=#id'
SET #ParmDefinition = N'#id tinyint,
#nameOUT varchar(30) OUTPUT'
SET #IntVariable = 1
EXECUTE sp_executesql
#SQLString,
#ParmDefinition,
#id = #IntVariable,
#nameOUT=#name OUTPUT
SELECT #name
You can do something like below to store the result using sp_executesql with output parameter. Observed from here Assign result of dynamic sql to variable
declare #ret int
set #ret = 0
set #query='select name from studtable where id=1'
exec sp_executesql #query, N'#var int out', #ret out
select #ret

SP_ExecuteSQL with Parameters doesn't like Contains clause

I've been tasked with modifying a stored procedure so that it goes from looking like this:
DECLARE #ID nvarchar(10)
SET #ID = '0000000001'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT AppN FROM Apps WHERE CONTAINS(ID, ''"*'' + #ID + ''*"'')'
EXECUTE SP_EXECUTESQL #SQL
to using the parameter list for SP_EXECUTESQL and not string concatenation. The issue is that the following doesn't appear to work:
DECLARE #CID nvarchar(10)
SET #CID = '0000000001'
DECLARE #ID2 nvarchar(14)
SET #ID2 = '"*' + #ID + '*"'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT AppN FROM Apps WHERE CONTAINS(ID, ID2)'
DECLARE #ParamDefinition NCHAR(300)
SET #ParamDefinition = '#ID2 nvarchar(10)'
EXECUTE SP_EXECUTESQL #SQL, #ParamDefinition, #ID2
For whatever reason, the first set of statements works fine. The second does not. I get the following error message: Syntax error near '"' in the full-text search condition '"*00000000'.
If I remove 4 characters from #ID the second set of statements also works. Clearly it has something to do with the length of either #ID or the column ID but I can't figure out what.
You define #ID2 as nvarchar(10) in your parameters for the dynamic SQL.
It's actually 14 characters, so you are cutting off the end of it.
This outputs the correct variable for me:
DECLARE #CID nvarchar(10)
SET #CID = '0000000001'
DECLARE #ID2 nvarchar(14)
SET #ID2 = '"*' + #CID + '*"'
DECLARE #SQL nvarchar(200)
SET #SQL = 'SELECT #ID2'
DECLARE #ParamDefinition NCHAR(300)
SET #ParamDefinition = '#ID2 nvarchar(14)'
EXECUTE SP_EXECUTESQL #SQL, #ParamDefinition, #ID2