This is a dynamic stored procedure that will pass the database, linked server and state. When executing this stored procedure, it runs the stored procedure on the database on the linked server and gives the results back.
Working code - here the linked server is absolute and not passed as a variable
EXECUTE MYPROC 'CA','MYDB'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC MYLINKSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Not working code: here the linked server is passed through a variable.
I get a "Syntax error" at #LINKEDSERVER**.**master
EXECUTE MYPROC 'CA','MYDB','MYLINKSERVER'
CREATE PROCEDURE [dbo].[MYPROC]
(
#state varchar(2),
#DATABASE char(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL #VARCHAR(MAX)
SELECT #SQL = 'use ' + #DATABASE + ';
SELECT * FROM pubs.dbo.authors WHERE state = #state'
EXEC #LINKEDSERVER.master.dbo.sp_executesql
#SQL, N'#state char(2)', #state
Thanks in advance
Try this in your SP:
DECLARE #SQL VARCHAR(MAX);
SET #SQL = FORMATMESSAGE ( 'SELECT * FROM [%s].[%s].[dbo].[authors] WHERE [state] = ''%s'';', #LINKEDSERVER, #DATABASE, #state );
EXEC ( #SQL );
This would create the following SQL statement to be executed based on your sample parameters above:
SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';
I'm not sure what version of SQL Server you're running, so you may not be able to use FORMATMESSAGE, however, I'm sure you're familiar with concatenating strings.
I prefer to use OPENQUERY as it is usually much faster than using four-part query. So instead of SELECT * FROM [MYLINKSERVER].[MYDB].[dbo].[authors] WHERE [state] = 'CA';, try this:
SELECT * FROM OPENQUERY([MYLINKSERVER], '
SELECT * FROM [MYDB].[dbo].[authors] WHERE [state] = ''CA''
')
And your procedure will be something like this
CREATE PROCEDURE [dbo].[MYPROC]
(
#state CHAR(2),
#DATABASE VARCHAR(20),
#LINKEDSERVER VARCHAR(20)
)
AS
DECLARE #SQL NVARCHAR(500)
SET #SQL = N'SELECT * FROM OPENQUERY(' + QUOTENAME(#LINKEDSERVER) + ', ''
SELECT * FROM ' + QUOTENAME(#DATABASE) + '.dbo.authors WHERE state = ''''' + #state + '''''
'')'
EXEC SP_EXECUTESQL #SQL
--PRINT #SQL -- To see the final query to execute
Or you can use FORMATMESSAGE as the answer given by Critical Error.
SET #SQL = FORMATMESSAGE ('SELECT * FROM OPENQUERY([%s], ''
SELECT * FROM [%s].[dbo].[authors] WHERE [state] = ''''%s'''''');', QUOTENAME(#LINKEDSERVER), QUOTENAME(#DATABASE), #state
);
EXEC (#SQL);
Use QUOTENAME to avoid SQL injection. As the other parameter is limited to char(2), I guess it should be safe.
Related
Create Function fnRMatrixColorGet1(
#RMID varchar(20)
)
returns varchar(100)
as
begin
EXEC (N'SELECT ' + 'C'+#RMID + ' FROM vwemployeeget where empid='+#RMID)
return
end
As Gordon wrote in the comments, user defined functions in SQL Server can't execute dynamic SQL.
From Create User-defined Functions:
User-defined functions cannot make use of dynamic SQL or temp tables. Table variables are allowed.
However, you can create a stored procedure to do that:
CREATE PROCEDURE stpRMatrixColorGet1
(
#RMID varchar(20)
#MatrixColor varchar(100) OUTPUT
)
AS
DECLARE #Sql nvarchar(4000),
#Column sysname = N'C' + #RMID;
-- White list column name since it can't be parameterized
IF EXISTS
(
SELECT 1
FROM Information_Schema.Columns
WHERE Table_Name = 'vwemployeeget'
AND Column_Name = #Column
)
BEGIN
SET #SQL = N'SELECT #MatrixColor = QUOTENAME('+ #Column +') FROM vwemployeeget where empid = #RMID'
-- Safely execute dynamic SQL using sp_ExecuteSql
EXEC sp_ExecuteSql
#Sql,
N'#RMID varchar(20), #MatrixColor varchar(100) OUTPUT',
#RMID,
#MatrixColor OUTPUT
END
I am trying to execute this query:
declare #tablename varchar(50)
set #tablename = 'test'
select * from #tablename
This produces the following error:
Msg 1087, Level 16, State 1, Line 5
Must declare the table variable "#tablename".
What's the right way to have the table name populated dynamically?
For static queries, like the one in your question, table names and column names need to be static.
For dynamic queries, you should generate the full SQL dynamically, and use sp_executesql to execute it.
Here is an example of a script used to compare data between the same tables of different databases:
Static query:
SELECT * FROM [DB_ONE].[dbo].[ACTY]
EXCEPT
SELECT * FROM [DB_TWO].[dbo].[ACTY]
Since I want to easily change the name of table and schema, I have created this dynamic query:
declare #schema sysname;
declare #table sysname;
declare #query nvarchar(max);
set #schema = 'dbo'
set #table = 'ACTY'
set #query = '
SELECT * FROM [DB_ONE].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table) + '
EXCEPT
SELECT * FROM [DB_TWO].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table);
EXEC sp_executesql #query
Since dynamic queries have many details that need to be considered and they are hard to maintain, I recommend that you read: The curse and blessings of dynamic SQL
Change your last statement to this:
EXEC('SELECT * FROM ' + #tablename)
This is how I do mine in a stored procedure. The first block will declare the variable, and set the table name based on the current year and month name, in this case TEST_2012OCTOBER. I then check if it exists in the database already, and remove if it does. Then the next block will use a SELECT INTO statement to create the table and populate it with records from another table with parameters.
--DECLARE TABLE NAME VARIABLE DYNAMICALLY
DECLARE #table_name varchar(max)
SET #table_name =
(SELECT 'TEST_'
+ DATENAME(YEAR,GETDATE())
+ UPPER(DATENAME(MONTH,GETDATE())) )
--DROP THE TABLE IF IT ALREADY EXISTS
IF EXISTS(SELECT name
FROM sysobjects
WHERE name = #table_name AND xtype = 'U')
BEGIN
EXEC('drop table ' + #table_name)
END
--CREATES TABLE FROM DYNAMIC VARIABLE AND INSERTS ROWS FROM ANOTHER TABLE
EXEC('SELECT * INTO ' + #table_name + ' FROM dbo.MASTER WHERE STATUS_CD = ''A''')
Use:
CREATE PROCEDURE [dbo].[GetByName]
#TableName NVARCHAR(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #sSQL nvarchar(500);
SELECT #sSQL = N'SELECT * FROM' + QUOTENAME(#TableName);
EXEC sp_executesql #sSQL
END
You can't use a table name for a variable. You'd have to do this instead:
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = 'SELECT * from yourtable'
EXEC (#sqlCommand)
You'll need to generate the SQL content dynamically:
declare #tablename varchar(50)
set #tablename = 'test'
declare #sql varchar(500)
set #sql = 'select * from ' + #tablename
exec (#sql)
Use sp_executesql to execute any SQL, e.g.
DECLARE #tbl sysname,
#sql nvarchar(4000),
#params nvarchar(4000),
#count int
DECLARE tblcur CURSOR STATIC LOCAL FOR
SELECT object_name(id) FROM syscolumns WHERE name = 'LastUpdated'
ORDER BY 1
OPEN tblcur
WHILE 1 = 1
BEGIN
FETCH tblcur INTO #tbl
IF ##fetch_status <> 0
BREAK
SELECT #sql =
N' SELECT #cnt = COUNT(*) FROM dbo.' + quotename(#tbl) +
N' WHERE LastUpdated BETWEEN #fromdate AND ' +
N' coalesce(#todate, ''99991231'')'
SELECT #params = N'#fromdate datetime, ' +
N'#todate datetime = NULL, ' +
N'#cnt int OUTPUT'
EXEC sp_executesql #sql, #params, '20060101', #cnt = #count OUTPUT
PRINT #tbl + ': ' + convert(varchar(10), #count) + ' modified rows.'
END
DEALLOCATE tblcur
You need to use the SQL Server dynamic SQL:
DECLARE #table NVARCHAR(128),
#sql NVARCHAR(MAX);
SET #table = N'tableName';
SET #sql = N'SELECT * FROM ' + #table;
Use EXEC to execute any SQL:
EXEC (#sql)
Use EXEC sp_executesql to execute any SQL:
EXEC sp_executesql #sql;
Use EXECUTE sp_executesql to execute any SQL:
EXECUTE sp_executesql #sql
Declare #tablename varchar(50)
set #tablename = 'Your table Name'
EXEC('select * from ' + #tablename)
Also, you can use this...
DECLARE #SeqID varchar(150);
DECLARE #TableName varchar(150);
SET #TableName = (Select TableName from Table);
SET #SeqID = 'SELECT NEXT VALUE FOR ' + #TableName + '_Data'
exec (#SeqID)
Declare #fs_e int, #C_Tables CURSOR, #Table varchar(50)
SET #C_Tables = CURSOR FOR
select name from sysobjects where OBJECTPROPERTY(id, N'IsUserTable') = 1 AND name like 'TR_%'
OPEN #C_Tables
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
WHILE ( #fs_e <> -1)
BEGIN
exec('Select * from ' + #Table)
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
END
This is my Store Procedure :
ALTER PROC [dbo].[Details]
#name nvarchar(20)
AS
BEGIN
SELECT Id FROM Client WHERE name in (#Name)
END
If i am passing one value output is Coming:
Like this i am passing:
EXEC [dbo].[Details] 'Monday'
For Two values Like this :
If i am passing two value output not is Coming:
To get this in which way i need to send parameter
currently I am passing Two parameter like This
EXEC [dbo].[Details] ''Monday','Wipro'';
Thank u in advance
You can try this code to extract table from your parameter:
declare #sql nvarchar(max)=
'abc,def,ghi,jkl'
set #sql = replace(#sql,',','''),(''')
set #sql = 'select *
from (values ('''+#sql+''')
) a ( Value )
'
PRINT(#sql)
exec sp_executesql #sql
Then use execution result with IN-condition. You can configure this part with any delimiter.
Try this one:
ALTER PROCEDURE dbo.[Details]
#name NVARCHAR(30)
AS
DECLARE #Sql VARCHAR(MAX)
SET #name = REPLACE(#name,',',''',''')
SET #Sql = 'SELECT
*
FROM table1
WHERE username IN
(
''' + #name + '''
)'
EXEC (#Sql)
EXEC [dbo].[Details] 'mohan,prashant'
I need to get data from a table in a database who's database name will be determined as a variable during a trigger. I then, knowing this variable need to get a seqno from a table in the determined database for a item which was also determined as a variable during a trigger.
I am trying this route as I assume I need to build the SQL statement before I set it to a variable.
This is not working and I need to know the best way on how I can do this:
DECLARE #SU_SEQNO INTEGER, #SU_NAME VARCHAR(50), #SU_OWNER VARCHAR(15), #SUD_SEQNO INTEGER, #SQL NVARCHAR(500)
SET #SU_OWNER = 'XXX'
SET #SU_NAME = '1ABC234'
SET #SQL ='SELECT #SUD_SEQNO=SEQNO FROM ' + (#SU_OWNER) + '.SU_MAIN
WHERE UNITNAME= ' + #SU_NAME
SET #SUD_SEQNO = (EXECUTE (#SQL))
Thanks alot for any help with this
From: Get result from dynamic SQL in stored procedure
SET #SQL = N'SELECT DISTINCT #FiscalYear = FiscalYear FROM ' + #DataSource;
EXEC sp_executesql #SQL, N'#FiscalYear INT OUTPUT', #FiscalYear OUTPUT;
PRINT #FiscalYear;
I'd re-engineer to use the sp_executesql method as shown above. That should do the trick.
I have amended the code, and it works
declare #su_owner varchar(15) = 'DBTEST'
declare #SU_SEQNO INTEGER=1, #SUD_SEQNO INTEGER=0, #SQL NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500), #SU_NAME_INPUT VARCHAR(50)='SU123'
SET #SU_NAME_INPUT = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SU_NAME = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SQL = N'SELECT #sud_seqnoOUT=MAX(SEQNO) FROM ' + quotename(#su_owner) + '.[dbo].[SU_MAIN] WHERE UNITNAME]=#SU_NAME_INPUT' ;
SET #ParmDefinition = N'#SU_NAME_INPUT VARCHAR(50),#sud_seqnoOUT INT OUTPUT'
EXEC sp_executesql #SQL,#ParmDefinition,#SU_NAME_INPUT = #SU_NAME,
#sud_seqnoOUT = #SUD_SEQNO OUTPUT
I have a Stored Procedure (SP) in which I pass in one value. In this SP, I am trying to create/populate a Temp Table from the result of another SP that is on a Linked/remote server. That is I am trying to executute an SP in my SP and populate a temp table which my query will use.
I have tried using the following syntax, but it does not work as it seems openquery does not like the "+" or the #param1 parameter.
select * into #tempTable
from openquery([the Linked server],'exec thelinkedSPname ' + #param1)
If I have the parameter value hard coded in this it works fine.
select * into #tempTable
from openquery([the Linked server],'exec thelinkedSPname 2011')
I have also gone as far as manually building the temp table and trying to execute the linked SP but that does not work as well.
create table #tempTable(
.
.
.
)
insert into #tempTable
(
.
.
.
)
Exec [the Linked server],'exec thelinkedSPname ' + #param1
Any suggestions as to how to populate a temp table from within a SP that executes a SP via a linked server. Note the above SQL is only pseudo code
I think you are gonna need dynamic SQL, since you can't pass the parameter to an OPENQUERY like that (but first visit this link) So you would have something like this:
create table #tempTable(
.
)
DECLARE #param1 VARCHAR(10), #Query VARCHAR(8000)
SET #param1 = '2011'
SET #Query = '
SELECT *
FROM OPENQUERY([Linked Server],''exec thelinkedSPname '' + #param1+''')'
INSERT INTO #tempTable
EXEC(#Query)
With the usual disclaimers about guarding dynamic SQL, you can do this without OPENQUERY etc. Just call sp_executesql remotely:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'EXEC thelinkedSPname ' + #param1 + ';';
INSERT #temptable EXEC [LinkedServerName].database.dbo.sp_executesql #sql;
I use this method quite frequently:
DECLARE #YEAR AS VARCHAR(4) SET #YEAR = 2015
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #OPENQUERY AS VARCHAR(MAX)
DECLARE #LINKEDSERVER AS VARCHAR(MAX) SET #LINKEDSERVER = 'Name of Linked Server here with out brackets'
SET #SQL='
Select
tbl1.*
FROM
dbo.Table_ON_LINKED_SERVER AS tbl1
WHERE
tbl1.number_id = ''''1''''
AND YEAR(tbl1.DATETIME) = ' + #YEAR + '
AND tbl1.NAME <> ''''%JONES%''''
'''
SET #OPENQUERY = 'SELECT * INTO ##GLOBAL_TEMP_NAME FROM OPENQUERY(['+ #LINKEDSERVER +'],''' + #SQL + ')'
--SELECT #OPENQUERY
EXEC(#OPENQUERY)
Two words: Dynamic Query.
Try this:
DECLARE #TSQL varchar(8000)
SELECT #TSQL = 'SELECT * INTO #tempTable FROM OPENQUERY([the Linked server],''exec [the Linked server].DBName.dbo.thelinkedSPname ' + #param1 + ''')'
EXEC (#TSQL)
This is well documented here:
How to pass a variable to a linked server query
With some care you could use a shared temp table:
DECLARE #Qry AS VARCHAR(MAX)
SET #Qry = 'select * into ##tempTable from openquery([the Linked server],''exec thelinkedSPname ' + #param1 + ''')'
EXEC (#Qry)
-- Now just use the shared Temp table, or I suppose you could copy it to a temp table just as you wanted it:
SELECT * INTO #tempTable FROM( SELECT * FROM ##tempTable)tbl
DROP TABLE ##tempTable