Is it possible to construct a dynamic query to for a linked server (and if so how)?
For example:
#linkedServer varchar(50)
#var1 varchar(10)
#var2 varchar(10)
select *
from openquery(#linkedServer,
'select c1,c2
from t1
where p1 = #var1
and p2= #var2')
example
exec ('select * from openquery(' + #linkedServer +
', ''select c1,c2 from t1 where p1 = '' + #var1 + ''and p2= '' + #var2 + ''')
make sure to read The Curse and Blessings of Dynamic SQL to protect against SQL injection
see EXEC() at Linked Server section of The Curse and Blessings of Dynamic SQL by Erland Sommarskog
from that article:
A special feature added in SQL 2005 is
that you can use EXEC() to run
pass-through queries on a linked
server. This could be another instance
of SQL Server, but it could also be an
Oracle server, an Access database,
Active directory or whatever. The SQL
could be a single query or a sequence
of statements, and could it be
composed dynamically or be entirely
static. The syntax is simple, as seen
by this example:
EXEC('SELECT COUNT(*) FROM ' + #db +
'.dbo.sysobjects') AT SQL2K
SQL2K is here a linked server that has
been defined with sp_addlinkedserver.
Related
We have a SQL Server 2014, with about 20+ Linked (oracle) Servers.
From time-to-time, I need to check the USER ID (on the Oracle side) status for all of these linked servers.
I currently use the following OPENQUERY statement for this:
SELECT * FROM OPENQUERY (MYLINKEDORACLESERVER,'SELECT * FROM SYS.USER_USERS')
Outputs:
However, because of the amount of servers, we're looking for a more automated way of doing this.
SYS.SERVERS outputs a list of all linked oracle servers (I've added the OPENQUERY syntax)
SELECT 'select * from openquery ('+ name +',''SELECT * FROM USER_USERS'')' FROM sys.servers
WHERE provider='OraOLEDB.Oracle'
Outputs:
How can I leverage the EXECUTE statement so that it automatically EXECUTES each OPENQUERY statement that it outputs?
Desired output:
One method would be to string aggregate them, and then execute them all in a single batch. As you're not in SQL Server 2017+, you'll be to use the old FOR XML PATH method:
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = STUFF((SELECT #CRLF + N'SELECT * FROM OPENQUERY('+ QUOTENAME(s.[name]) + ',''SELECT * FROM USER_USERS'');'
FROM sys.servers
FOR XML PATH(N''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,2,N'');
PRINT #SQL; --Your best friend
EXEC sys.sp_executesql #SQL;
I want to be able to execute remote queries based on the results of a local query.
For instance:
DECLARE #REMOTESERVER VARCHAR(10)
Select TOP 1 #REMOTESERVER = RemoteServer from TABLE
--Execute the next query on a remote server from the value I retrieved above
Select * from tblCustomers
What RDBMS are you using? Some will not support a pure sql way of doing this. Others, like SQL Server, might support this scenario. Is the remote server accessible via a linked server that you can access. You could then use dynamic sql to create your sql string. Something like this should work in SQL Server:
SET #Sql = 'SELECT * FROM [' + #RemoteServer + '].dbname.schema.tblCustomers'
EXEC #Sql
Here is a post about linked servers: https://stackoverflow.com/a/4091984/1073631
EDIT
The final goal is to call a stored procedure hosted in sybase with input and output parameters from SQL Server 2008 via Linked Server
I think title is pretty clear.
My goal is to execute a stored procedure hosted in Sybase SQL Anywhere 8 in SQL Server 2008 through the linked server I already created.
Any SQL query made through the linked server is working.
In addition I was able to execute a function but I don't now how to get the return value like that
EXEC ('CALL "dbname"."procedurename"(''param1'', ''param2'', ''param3'')') AT LinkedServerAlias;
Thanks 4 all your help!
Mauro
can you use four part naming convention?
like
exec LinkedServerName.dbname.dbo.procedurename #param1, #param2, #param3
I was finally able to do it by calling
SELECT * FROM OPENQUERY([LinkedServer], 'SELECT "dbname"."spname"(#p1,#p2, #p3)')
I'll add comments and example as soon as I experiment it.
4 part object names are valid only for SQL Server linked servers.
You have to have your EXEC inside an OPENQUERY
SELECT * FROM OPENQUERY([LinkedServer], 'EXEC MyDB.MyScheme.MyProc.spname #p1, #p2, #p3')
Now, you can't parametrise OPENQUERY calls so you have use dynamic SQL
DECLARE #sql nvarchar(4000), #linkedsql nvarchar(4000)
SET #sql = 'EXEC MyDB.MyScheme.MyProc.spname ' + CAST(#p1value as int) + ...
SET #linkedsql = 'SELECT * FROM OPENQUERY(LinkedServer, ''' + #sql + ''')'
EXEC (#linkedsql)
I need to get the table name to query from a table.
var tableName = "select tableName from tableList where type='A';"
Then subsequently use that table name in another query.
"select * from" + tableName
Transact SQL/stored procedures are new to me in general so any help would be appreciated. I didn't design the database and unfortunately can't really change it to be a better design as much as I would love to!
My question is - is this possible from one stored procedure and if so can anyone mock up how I'd do it.
Or if there are any better ways anyone can think of (bar redesigning the database!)
Thanks
Maybe via dynamic SQL
DECLARE #String AS VARCHAR(8000)
DECLARE #TableName AS VARCHAR(50)
DECLARE #Results AS VARCHAR(8000)
SET #TableName = (select top 1 tableName from tableList where type='A')
SET #String = 'Select * from ' + #TableName
SET #Results = #String + #TableName
EXEC #Results
You can either use execas #kevchadders suggested or you can use sp_executesql, read The Curse and Blessings of Dynamic SQL for an excellent explantion on dynamic SQL.
You should use dynamic SQL to achieve that.
Basically, you execute your query using sp_executesql or exec, and store the result to a, kinda, staging table to be processed further:
declare #sql = varchar(8000);
select #sql = 'insert into resulttbl select * from ' + #tableName;
exec sp_executesql(#sql);
-- further process using resulttbl
Or
insert into resulttbl
exec ('select * from ' + #tableName);
-- further process using resulttbl
Anyway, you should read the following article for a better explanation: The Curse and Blessings of Dynamic SQL
You can directly write
select * from (select tableName from tableList where type='A') X
On my SQL 2005 server, I have a linked server connecting to Oracle via the OraOLEDB.Oracle provider.
If I run a query through the 4 part identifier like so:
SELECT * FROM [SERVER]...[TABLE] WHERE COLUMN = 12345
It takes over a minute to complete. If I run the same query like so:
SELECT * FROM OPENQUERY(SERVER, 'SELECT * FROM TABLE WHERE COLUMN = 12345')
It completes instantly. Is there a setting I'm missing somewhere to get the first query to run in a decent period of time? Or am I stuck using openquery?
In your first example using "dot" notation, client cursor engine is used and most things are evaluated locally. If you're selecting from a large table and using a WHERE clause, the records will be pulled down locally from the remote db. Once the data has been pulled across the linked server, only then is the WHERE clause is applied locally. Often this sequence is a performance hit. Indexes on the remote db are basically rendered useless.
Alternately when you use OPENQUERY, SQL Server sends the sql statement to the target database for processing. During processing any indexes on the tables are leveraged. Also the where clause is applied on the Oracle side before sending the resultset back to SQL Server.
In my experience, except for the simplest of queries, OPENQUERY is going to give you better performance.
I would recommend using OpenQuery for everything for the above reasons.
One of the pain points when using OpenQuery that you may have already encountered is single quotes. If the sql string being sent to the remote db requires single quotes around a string or date date they need to be escaped. Otherwise they inadvertantly terminate the sql string.
Here is a template that I use whenever I'm dealing with variables in an openquery statement to a linked server to take care of the single quote problem:
DECLARE #UniqueId int
, #sql varchar(500)
, #linkedserver varchar(30)
, #statement varchar(600)
SET #UniqueId = 2
SET #linkedserver = 'LINKSERV'
SET #sql = 'SELECT DummyFunction(''''' + CAST(#UniqueId AS VARCHAR(10))+ ''''') FROM DUAL'
SET #statement = 'SELECT * FROM OPENQUERY(' + #linkedserver + ', '
SET #Statement = #Statement + '''' + #SQL + ''')'
EXEC(#Statement)