SQL Server Linked Server Join - sql

I have added a linked server in my sql server 2008. I want to fetch data from a table and a table valued function residing on my linked server and join this data on a local table by following below given naming convention.
<server>.<database>.<schema>.<table>
However my first problem is I need to fetch <server> part from a table. So when I try to do something like following it fails
Select * FROM #ServerNameVariable.database.dbo.myTable
Any idea how can I form fully qualified linked server table name with a user defined variable ?
My SP is as follows
CREATE PROCEDURE TEST_SP
AS
BEGIN
DECLARE #NetworkDBName VARCHAR(255)
SET #NetworkDBName = '[MyLinkedServerName]'
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select * from #NetworkDBName + '.' + testDatabase.dbo.Invoice_tb
END
GO

You cannot use variables in place of database, schema or table names.
Instead you can build and execute dynamic SQL statements, using sp_ExecuteSQL.
This example won't work, as the server name is seen as a string and not a server object.
Failed Example
/* Anti-pattern.
* Does not work.
*/
DECLARE #Server SYSNAME = 'Server001';
SELECT
*
FROM
#Server.Database1.dbo.Table1
;
This example shows a method that does work. Here the SQL statement is built as a string, which is then executed.
/* Dynamic SQL statement.
* Will work.
*/
DECLARE #Server SYSNAME = 'Server001';
DECLARE #Statement NVARCHAR(255);
SET #Statement = 'SELECT * FROM ' + QUOTENAME(#Server) + '.Database1.dbo.Table1;';
EXECUTE sp_ExecuteSQL #Statement;
As ever; please be careful when generating and executing dynamic SQL statements. You do not want to open yourself up to SQL injection attacks. Look into OPENROWSET or check the passed server name against the code kindly supplied by #Devart above (SELECT name FROM sys.servers WHERE server_id > 0) before executing.
EDIT 1: Added more detail to the paragraph on SQL injection.
EDIT 2: Removed square brackets from 2nd example query, replaced with QUOTENAME, as per #TTs comment.

Use the name of link server it will a 4 part qualifier e.g
Select * From [Link Server Name ].[Database].[Schema].[Table]

Related

Why is the openquery returning 0 rows on SQL server but has 900k rows in the target Server?

Need help to figure ut why the remote query I execute on the server return 0 rows , but the same query returns over 900k rows in the target DB.
the string is less 8000 characters long so I won't post it here. but this is the sctructure basically:
declare #SQL varchar(MAX);
declare #D varchar(15);
declare #Per varchar(15);
declare #NextPer varchar(15);
declare #NextYPer varchar(15);
set #D = N'01-JUN-2019'
set #Per = N'2020004';
set #NextYPer = N'2021004'
set #NextPer = N'2020005'
set #SQL = N' SELECT ...... '
set #SQL = N'select * from openquery ([LK1], "'+#SQL+'")';
execute( #SQL);
print #SQL;
Note: the linked server works and is used on other openqueries with shorter strings successfully. I tried using EXECUTE (#SQL) AT and I still get 0 rows. When i exexute the print output directly on the Oracle DB , the query runs for about 15 min and gives results.
First off, OPENQUERY requires the second parameter to be a query string. A string in SQL Server is written between single quotes. From OPENQUERY documentation:
OPENQUERY ( linked_server ,'query' )
Not only that, the SQL that appears in that string, needs to have any single-quotes that appear in the query to be doubled. Suppose you had SQL you wanted to execute the following query:
SELECT * FROM some_table WHERE name='TT.';
You would write this as:
OPENQUERY(lks,'SELECT * FROM some_table WHERE name=''TT.''')
But if you have this in a dynamic SQL statement, this would become
DECLARE #s VARCHAR(MAX);
SET #s='SELECT * FROM OPENQUERY(lks,''SELECT * FROM some_table WHERE name=''''TT.'''''')';
So that's some explosion of single quotes for even the more trivial SQL queries. Count ye quotes, make sure the query itself is up to snuff (i.e. quotes have been properly doubled).
Thanks all for the input.
The root cause is simply the format of the Date parameter, which didn't run correctly on the linked server.
All I had to do is change my query to use this:
SO_BOOK_DATE < to_date(''#D'' , ''DD-MON-YYYY'')
instead of
SO_BOOK_DATE < ''#D'' .

How to use variable for server name in SQL Server stored procedure

I have two database servers, server1 and server2, which are our diff environment of our legacy system. I have to write a stored procedure for getting data which is communicate with one of the env.
I want a way so that I can easily switch the env
Like:
Declare #Server nvarchar(20)
set #Server="server1"
select *
from #Server.global.dbo.tblaccount
Parameters cannot be used for identifiers -- column names, table names, schema names, server names, function names, and so on.
You can do this with dynamic SQL:
declare #Server nvarchar(20);
declare #sql nvarchar(max);
set #Server = 'server1';
set #sql = 'select * from [Server].global.dbo.tblaccount';
set #sql = replace(#sql, '[Server]', #Server);
exec sp_executesql #sql;
use synonyms:
create synonym mylocalschema.RemoteTable for server1.database.schema.table;
to be referenced as:
select top 10 * from mylocalschema.RemoteTable;
depending on env the synonyms will be a reference to the right server and the code (sp, views, triggers, whatever) will be the very same for both.
the only duplicate item is the script to create synonyms: one for server1 and another copy for server2 (or maybe the same script built with dynamic sql...).

Remote table-Valued Function Calls are not allowed

How can I make this work?Im running a table valued function from a remote linked server. i tried adding no lock to this 4 part naming but still i get the same error. Im using mssql-2008
select * from [110.10.10.100].testdbname.dbo.ufn_getdata('4/25/2013') as tb;(NOLOCK)
You need to add WITH (NOLOCK). Not entirely sure why but I just ran into this issue today and this solved my issue.
SELECT *
FROM [110.10.10.100].testdbname.dbo.ufn_getdata('4/25/2013') AS tb WITH (NOLOCK);
Nolock doesn't work for me.
However, using OPENQUERY does...
Replace DMS_DB.dbo.tfu_V_DMS_Desktop(''de'')' with [110.10.10.100].testdbname.dbo.ufn_getdata(''4/25/2013'')
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tfu_V_DMS_Desktop]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[tfu_V_DMS_Desktop]
GO
CREATE FUNCTION [dbo].[tfu_V_DMS_Desktop]
(
#param1 int
)
RETURNS table
AS
RETURN
(
-- Add the SELECT statement with parameter references here
-- SELECT 0 as abc
SELECT * FROM OPENQUERY(CORDB2008R2, 'SELECT * FROM DMS_DB.dbo.tfu_V_DMS_Desktop(''de'')')
)
GO
On a footnote, the problem is OPENQUERY doesn't allow a variable, so you cannot have variable parameters.
You can however reference all tables and views as views from a remote server, and just create the table-valued function 1:1 locally. This will probably be slow, however.
Following SQL OpenQuery command should be working
Parameter values which are surrounded with ' are replaced with double ''
So in this case there is no need to create a stored procedure on the target instance database
SELECT *
FROM OPENQUERY(
[110.10.10.100],
'SELECT * FROM testdbname.dbo.ufn_getdata(''4/25/2013'')'
) as oq
Also make sure that RPC OUT is set to TRUE in linked server options. This option also needed when you try to execute stored procedure on linked server. Otherwise you will get following error.
Server 'servername' is not configured for RPC
See this answer:
Use OPENQUERY
Replace SP call with SELECT ... FROM fn() query and it should work.
This is the example of calling a remote SQL user defined function returning a table as output in SQL Server 2014. It is working for me.
Declare #Param1 Varchar(10)
Declare #SqlText nvarchar(4000)
Set #Param1 = 'xxx'
Set #SqlText = 'SELECT * FROM Database.dbo.ufn_Function (''' + #Param1 + ''')'
EXEC LinkedServer.Database.dbo.sp_executesql #SqlText

SQL Server stored procedures to copy tables

I have to move a table into other table using a stored procedure by passing the table names as parameters.
Syntax is:
alter procedure [dbo].[moving]
(
#to_table varchar(50),
#from_table varchar(50)
)
as
begin
EXEC('Select * into '+#to_table+'from '+#from_table)
end
while executing by.
exec moving newtable,hello
It is giving an error:
Incorrect syntax near 'hello'
pls anyone give solution for this
Try:
exec moving 'newtable','hello'
It also looks like you are going to need to fix your SP. You will need a space before from:
EXEC('Select * into '+#to_table+' from '+#from_table)
Read EXECUTE syntax and try,
EXEC moving 'newtable','hello'
SELECT ... INTO needs to create table, if table exists use INSERT INTO ... SELECT ..FROM
AND
in your case you need to run SP in such a way:
EXEC dbo.moving 'table1', 'table2'
BUT
EXEC('Select * into '+#to_table+' from '+#from_table)
will not work, you need to rewrite it with variable:
declare #sql nvarchar(max)
SET #sql = N'Select * into ['+#to_table+N'] from ['+#from_table+N']'
EXEC(#sql)
BUT
you also need to worry of sql injections and complex table names AT LEAST, so - for complex table names I already framed your tables with square braces, and you need to do something to prevent sql injections.
And once more - SELECT...INTO works only if you creating new table with name from #to_table parameter
add an extra space after single quote and FROM
EXEC('Select * into ' + #to_table + ' from ' + #from_table)

Execute stored proc with OPENQUERY

I have SQL Server 2008 with a linked Sybase server and I am trying to execute a stored procedure on the Sybase server using OPENQUERY. If I have a stored proc that doesn't take parameters it succeeds fine. If I have a stored proc with parameters it fails. I even tried a very basic stored proc that only took an int an that still failed. Below is the syntax I am using:
select * from
OPENQUERY([LINKSERVER],'exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
Msg 7357, Level 16, State 2, Line 3
Cannot process the object "exec database.user.my_stored_proc 'AT','XXXX%','1111',1". The OLE DB provider "ASEOLEDB" for linked server "LINKSERVER" indicates that either the object has no columns or the current user does not have permissions on that object.
As the proc will execute just fine without parameters, I don't think it is a permission issue.
This worked for me,
SELECT * FROM OPENQUERY(LOCALSERVER, 'SET FMTONLY OFF EXEC snr.dbo.GetAllSignals #controlRunId = 25, #experimentRunId = 26')
I was creating temporary tables, and that's why i got access denied
Here is more info http://www.sommarskog.se/share_data.html#OPENQUERY
I create a sp that doesn't return any value and it doesn't work.
Your SP in mysql have to return a value!
for example I do this in "mysql":
CREATE DEFINER=`root`#`localhost` PROCEDURE `MyPro`(IN `Name` VARCHAR(50), IN `Id` INT, OUT `Result` INT)
MODIFIES SQL DATA
BEGIN
DECLARE Result INT;
SET Result = 0;
INSERT into MyTable (Id,Name) VALUES(Id,Name);
SELECT Result;
END
That "Id" and "Name" is input parameter and "Result" is output parameter
and create linked server in SQL SERVER and call it like this:
select * from openquery
(
Test,'call mydb.MyPro(''Name'',''16'', #P0);'
)
It works for me :D
Linked Servers and OPENQUERY, Gems to MS SQL Server...that are wolves in sheep clothing. I've found the following solutions to work when dealing with parameters
If the SP is basically just SELECT statements, the move the same to a VIEW and just pass SQL statements via OPENQUERY.
Build the OPENQUERY as a string and then use execute_sql.
You could also see if it works to precede exec with SET FMTONLY ON:
OPENQUERY([LINKSERVER],'SET FMTONLY ON; exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
If you try this and it works, you should probably Google FMTONLY+OPENQUERY to get an idea of what it means.
Try this,
SELECT * FROM OPENQUERY(linked_server_name, 'SELECT postgres_procedure_name (parameters)');
I experienced a very similar issue, but my SP wasn't taking any parameters.
I tried experimenting with altering the query sent through the openquery to include 'SET NOCOUNT ON' and 'SET FMTONLY OFF' but this had no difference.
The only solution that worked for my stored procedure was dropping the existing version, and altering the code to specifically 'SET NOCOUNT ON'
After doing this I was able to successfully run my stored proc through my linked server connection.
First of all you have to add hard code text fields then you have to
replace it by your parameters value like FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType
DECLARE #startdate varchar(255) = '2019-12-17'
DECLARE #enddate varchar(255) = '2019-12-17'
Set #SQL = 'SELECT * FROM OPENQUERY(' + quotename(#LinkedServer) + ',' + '''' +
'SET FMTONLY OFF; exec [TAP].[dbo].[GetAttendanceList] ' + 'FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType,1'')'
You have to replace your parameters values shown below
set #SQL=REPLACE(#SQL,'FromDate',+''''+''''+#startdate+''''+'''')
set #SQL=REPLACE(#SQL,'TillDate',+''''+''''+#enddate+''''+'''')
set #SQL=REPLACE(#SQL,'CompCode',+''''+''''+#CompCode+''''+'''')
set #SQL=REPLACE(#SQL,'AtnType',+''''+''''+''''+'''')
if #EmpID is Null
begin
set #SQL=REPLACE(#SQL,'EmpID','null')
end
if #DeptID is Null
begin
set #SQL=REPLACE(#SQL,'DeptID','null')
end
if #DesgId is Null
begin
set #SQL=REPLACE(#SQL,'DesgId','null')
end
if #LocationID is Null
begin
set #SQL=REPLACE(#SQL,'LocationID','null')
end
print #SQL
exec ( #SQL)