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;
Related
This question already has answers here:
SQL Server : query to loop through
(2 answers)
Dynamic query to Union multiple databases
(1 answer)
Closed last year.
I'm working with a server that creates a database every month with the same tables. The only thing that changes is the database name. I can use this query to create a table of the database names.
Select name
into DB_List
FROM master.sys.databases
where name Like '%DB%' and create_date > '2020-01-01'
Which returns:
DB013120,
DB022920,
DB033120,
etc.
I need to grab the different database names and input them into another query like the one below.
SELECT *
FROM [DB******].[dbo].[Table]
I know that I can use UNION but the problem is that the stored procedure will have to be manually updated every time there is a new database added. Currently running on SQL SERVER 2016
You can just build the UNION dynamically. For SQL Server 2017+:
DECLARE #sql nvarchar(max),
#base nvarchar(max) = N'SELECT *
FROM $db$.dbo.[Table]';
SELECT #sql = STRING_AGG
(REPLACE(#base, N'$db$', QUOTENAME(name)),
' UNION ALL ')
FROM master.sys.databases
WHERE name LIKE N'%DB%'
AND create_date > '20200101';
EXEC sys.sp_executesql #sql;
If you're using an older version (please always state that up front), you could use FOR XML PATH, which is a little messier and requires some whitespace-sensitive cleanup:
DECLARE #sql nvarchar(max),
#base nvarchar(max) = N'SELECT *
FROM $db$.dbo.[Table]';
SELECT #sql = STUFF((SELECT N' UNION ALL
' + REPLACE(#base, N'$db$', QUOTENAME(name))
FROM master.sys.databases
WHERE name LIKE N'%DB%'
AND create_date > '20200101'
FOR XML PATH(''), TYPE).value(N'./text()[1]',N'nvarchar(max)'),1,10, '');
EXEC sys.sp_executesql #sql;
I am trying to run dynamic SQL in SQL Server 2016, like this:
declare #SQL varchar(MAX);
set #SQL='SELECT top 1 * INTO Table 1 FROM
OPENROWSET(''Microsoft.ACE.OLEDB.12.0'', etc... (string aprox. 450 char)
EXECUTE sp_executesql #SQL;
For some reason, the variable #SQL is truncated to 256 characters. I already followed instructions in the article below and modify some SQL Server query settings but no result. See:
https://www.mssqltips.com/sqlservertip/2795/prevent-truncation-of-dynamically-generated-results-in-sql-server-management-studio/
Can you please advise, not sure what I am missing, it didn't happen in SQL Server 2008 that I used before. is there any additional setting in SQL Server 2016?
The problem is the sp_executesql uses nvarchar, so you should declare #sql as such, and also SET #sql = N'....:
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT top 1 * INTO Table 1 FROM
OPENROWSET(''Microsoft.ACE.OLEDB.12.0'', etc... '
EXECUTE sp_executesql #SQL;
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
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.