Linked SQL Server - Pass a use command or define default database - sql-server

I have a set of SQL queries that need to be run against 3 databases, they are stored on 2 different servers that have been linked.
All 3 databases have the the exact same tables and tables name, however the database names are different.
The queries have been written and all use just table names not the full database.dbo.table syntax so I can't use an automated find and replace on "linked.database1" to "linked.database2"
All the queries will always be executed through one server "Server1"
I'm trying to come up with a method of passing the queries to one of the linked servers but have a "use" command go through as it means I only have to change the database in the "use" line.
So far I have tried the following from Server1:
Select * from [Linked].Database.DBO.Table - Successful
Exec ('Select * from [Linked].Database.DBO.Table') - Successful
Direct on Server2 (using the account the linked server operates on):
EXEC ('Use Database; SELECT * from Table') - Successful
So with these above three I can ascertain
The login on Server1 can reach the databases needed and can access the data with a basic select and when passed with and Exec command.
The account on Server2 can run the Exec command and passing the "Use Database" line with Exec works on Server2.
However when I try using the below:
Select * from openquery ([Linked], 'Exec (Use Database; Select * from Table)')
I get the following error:
OLE DB provider "SQLNCLI10" for linked server "172.20.11.123" returned message "Deferred prepare could not be completed.".
Msg 8180, Level 16, State 1, Line 7
Statement(s) could not be prepared.
Msg 102, Level 15, State 1, Line 7
Incorrect syntax near ')'.
Msg 156, Level 15, State 1, Line 7
Incorrect syntax near the keyword 'Use'.
Have I messed up the syntax anywhere in the OpenQuery or can the USE command never be passed through OpenQuery.
If what I'm trying to do with OpenQuery and USE isn't possible then is there a way of passing the database you want the OpenQuery run against in the statement?
Or as a second thought, is there a way of putting together the Linked Server account so that it uses a particular database as its default database?

No, the way to do this, as far as I can tell, if you know which database you need to execute against:
DECLARE #database sysname = N'Database1';
DECLARE #sql nvarchar(max) = N'SELECT * FROM dbo.Table;';
DECLARE #exec nvarchar(4000) = N'[Linked].'
+ QUOTENAME(#database) + N'.sys.sp_executesql';
EXEC #exec #sql;
I'm not quite sure what this was trying to accomplish:
Select * from openquery ([Linked],
'Exec (Use Database; Select * from Table)')
But if you take out from that what you're trying to tell [Linked] to EXEC, it's this:
Exec (Use Database; Select * from Table)
Try that anywhere. Broken. You might get it to work like this, as #AlwaysLearning suggested:
Select * from openquery ([Linked],
'Exec (''Use Database; Select * from Table'')')
...but that's kind of, like, really gross, compared to the solution at the top. Unless you absolutely need to select from openquery for some reason.

Related

Table-Based Function using variables and OpenQuery

I am attempting to query data from our Oracle server via our SQL server. To perform this in a thin-client manner, I am using OpenQuery. I would like to build a single table-based function that can be used to query various linked tables as needed. I can't quite figure out the syntax to make this work. Here is what I have so far. Any help is greatly appreciated!
CREATE FUNCTION [dbo].[fnTEST](
#Table varchar (100),
#Fields varchar (1000),
#Condition varchar(5000)
)
RETURNS
#TEST TABLE()
AS
BEGIN
DECLARE #OPENQUERY nvarchar(4000);
DECLARE #TSQL nvarchar(4000);
SET #OPENQUERY = 'SELECT * FROM OPENQUERY([TEST-Link],'''
SET #TSQL = 'SELECT ' + #Fields + ' FROM TEST.' + #Table + ' WHERE ' + #Condition + ''')'
EXEC (#OPENQUERY+#TSQL)
END;
The error I am currently getting is:
Msg 102, Level 15, State 1, Procedure fnTEST, Line 12 [Batch Start Line 7]
Incorrect syntax near ')'.
Highlighted at #TEST TABLE()
This is all not recommended for a number of reasons, but here the big one is that, as indicated in the MS doc, you cannot use dynamic SQL from a user-defined function:
Before You Begin
Limitations and restrictions
...
User-defined functions cannot make use of dynamic SQL or temp tables. Table variables are allowed.
...
Here are some of the other problems with this approach:
Your dynamic SQL is injectable. You should never use dynamic SQL unless you understand what SQL Injection is and how to prevent it in your dynamic SQL code.
Using dynamic sql has potential security requirements and restrictions. In this case the dynamic SQL may not have the same rights as your account and may not be able to use an OPENQUERY.
The nature of Database and Server Trustworthy settings may block this anyway.
IMHO, OPENQUERY is not recommended (some disagree), and remote queries are better handled with Linked Servers and the Remote EXEC command.
You are trying to write a "Universal Query" here. Universal Queries are generally not a good idea and have security problems, even after you fix the SQL Inject issues. It's better to define the specific queries needed by your app and code them as stored procedures and/or fixed queries using parameters only for WHERE conditions.
A SQL Function is not the right place for all of this anyway. You should regard a SQL table function as akin to a View, but with parameters for your WHERE clause. You should not treat it as a way to magically do anything.
The way that I would do something link this is as follows:
Define the explicit queries/datasets that your app needs from the Oracle Database.
Write those queries as stored procedures, on the Oracle database.
Setup a Linked Server definition in your SQL Server database to the Oracle database. Configure the security for each side appropriately.
Write specific stored procedures on your SQL Server to call the corresponding procedures in the Oracle database. Use remote EXEC's to do this through the Linked Server definition.
(NOTE: Remote EXEC execution is done with the AT <linkedServer> clause).
Enable the linked server for rpc out and simplify this to
EXEC (#sql) at [TEST-Link]

How to use OPENQUERY to properly execute a Stored Procedure that updates a linked server table?

I'm having a hard time trying to figure this out. I'm using OPENQUERY to execute Stored Procedures on a linked server.
I managed to find a way to do it, by using the following:
SELECT *
FROM OPENQUERY(
[LINKEDSRV\SQLSRV],
'SET FMTONLY OFF; SET NOCOUNT ON; EXEC [Database_Name_Example].Data.usp_GetNames 5,''S''')
GO
The reason I use SET FMTONLY OFF and SET NOCOUNT ON is because when I tried the code above without them, this message appeared:
Msg 7357, Level 16, State 1, Line 1
Cannot process the object "EXEC [Database_Name_Example].Data.usp_GetNames 5,'S'". The OLE DB provider "SQLNCLI" for linked server "LINKEDSRV\SQLSRV" indicates that either the object has no columns or the current user does not have permissions on that object.
Reading a lot online helped me find the answer. This blog for example: http://www.sommarskog.se/share_data.html#OPENQUERY
So far so good, until I stomped into a Stored Procedure that use SELECT and UPDATE some tables on the linked server. When I execute the OPENQUERY I get the results from the SELECT statement but I noticed that it does not update the table.
The Stored Procedure goes like this:
CREATE PROCEDURE Data.usp_GetNames (#year tinyint=NULL, #online char(1)=NULL)
if #online = 'S'
BEGIN
select nam_codig, nam_desc from Names
where nam_status = 'P'
order by nam_date
UPDATE Names
SET nam_status = 'S'
where nam_status = 'P'
END
When I execute it directly in the linked server it updates the table, so the second time I execute it, there will be no more nam_status = 'P'
But if I execute it with OPENQUERY the results are the same, it doesn't UPDATE it just select the data.
What can I do to allow the permissions?
Thank you!!!

Find SQL query errors without executing the SQL query in SQL server

Is there any way to find the SQL query errors without executing the query in SQL server?
For example,
Use TestDB
Select * from Employee1
Consider TestDB doesn’t contain any table named “Employee1”. In this case, while we running this query, we will get the “Invalid object name Employee1” SQL error.
My question is that, after writing the query, is there any better approach to find these errors without executing?
I got a comment from my colleague is that use the sp_describe_first_result_set System stored procedure.
If you have 2012 and above you can use the sp that your colleague has mentioned.
If you use 2008 R2 and less then use
SET FMTONLY ON;
Select * from MyTabl;
SET FMTONLY OFF;
Msg 208, Level 16, State 1, Line 3
Invalid object name 'MyTabl'.
This will execute the query but not process any data. NOEXEC only parses the query so any objects that don't exist will not be flagged. NOEXEC checks syntax only. So what you want is either sp_describe_first_result_set or FMTONLY.
Alternatively if you have a select then you can also append to your where 1=2. For example
SELECT *
FROM MyTabl
WHERE 1=2
which gives them same result
Msg 208, Level 16, State 1, Line 3
Invalid object name 'MyTabl'

SQL Server SELECT INTO Using OPENROWSET With Variables?

I have a temp table where I want to store the results of a stored procedure. To execute the stored procedure, I need to use variable values for the Database name, Database Server, and Stored Procedure name that are stored in a table. I need to work out how to write the SELECT * INTO using the OPENROWSET with my variables. This is what I have so far but there are syntax errors:
SELECT * INTO #tmpAccountsRetrieved
FROM OPENROWSET(#TempDbName, 'Server=' + #TempDbServer + ';Trusted_Connection=yes;', 'EXEC ' + #TempStoredProcName)
I'm pretty rusty on SQL so any help is much appreciated!
Try to put these configurations in place before using openRowset:
-- FOR USING OPENROWSETS
EXEC sp_configure 'Ad Hoc Distributed Queries'
,1
RECONFIGURE
I think your syntax is correct.
So just Try to Go through this POST for more help

how to create utility stored procedure and run it like other sp_... utilities

I need to create a stored procedure one time and in one place only on my database server, but be able to run it from any database. However, I don't want to have to type database.schema.procedure_name every time I run it. I'd like to be able to use it like the built in procedures: sp_... is there any way to do this?
here is the procedure that I'm trying to create:
--actual procedure is more complex
CREATE PROCEDURE TestProcedure
AS
select * from sys.dm_exec_requests
go
here is how I'd like to run it from SQL Server Management Studio:
EXEC TestProcedure
--or
TestProcedure
however, you you get this error:
Msg 2812, Level 16, State 62, Line 1
Could not find stored procedure 'TestProcedure'.
everything runs fine if I run it with:
EXEC master.dbo.TestProcedure
--or
master.dbo.TestProcedure
you can run system procedures like this without any errors:
EXEC sp_help
--or
sp_help
Just create it in the master database and give it the sp_ prefix and it will work. SQL Server always checks the master database first for stored procedures (and other types of objects as well) with this prefix.
It will handle the datbase context for you as well as below.
USE master
create proc [dbo].[sp_test] as
select db_name()
GO
USE YourDB
EXEC master..sp_test /*Returns "master"*/
EXEC sp_test /*Returns "YourDB"*/
Edit:
Just following up Cade's comment to mark it as a system procedure. This seems like it might well be required in some circumstances. In SQL 2005+ you would use
EXEC sys.sp_MS_marksystemobject 'dbo.sp_test'

Resources