Passing concat query parameters to SQL OPENQUERY - sql-server

Due to the constraints within the workplace I have to use a local stored procedure to call another remote stored proc on a linked sql server, however the problem lies in passing a necessary parameter to the remote stored proc.
This is the query I constructed:
select *
from OPENQUERY([REMOTE_SRVR],'exec db.dbo.dwStoredProc_sp ''#id''')
In order to pass #id to the remote stored proc I understand I could concatenate the above as a string and then use exec
Something along the lines of:
set #query = 'select * from OPENQUERY([REMOTE_SRVR], ''EXEC db.dbo.dwStoredProc_sp '' #id '''''
exec(#query)
I cannot get the local stored proc to successfully call the other. The single quote mess doesn't help!
I get the error: Could not find stored procedure 's'

To help with the quote mess I like to do this in steps. It is more code but easier to understand. I am not sure from your example if #id is an integer. In that case you can lose the double quotes around __ID__.
set #query = 'EXEC db.dbo.dwStoredProc_sp ''__ID__'''
set #query = REPLACE(#query,'__ID__',#id)
set #query = REPLACE(#query,'''','''''')
set #query = REPLACE('SELECT * FROM OPENQUERY([REMOTE_SRVR], ''__REMOTEQUERY__'')','__REMOTEQUERY__',#query)

You could avoid dynamic queries by simply by using EXEC (..., ParamValue) AT LinkedServer (see product's documentation, example [L. Using a parameter with EXECUTE and AT linked_server_name]):
1) On target server:
CREATE PROCEDURE dbo.Proc1( #id NVARCHAR(50) )
AS
SELECT #id AS [id];
GO
2) On the source server you create the linked server and then you can call the stored procedure using EXEC ... AT ... syntax:
DECLARE #p1 NVARCHAR(50);
SET #p1 = N'DROP TABLE dbo.CocoJambo'
EXECUTE (N'dbo.Proc1 ? ' , #p1 ) AT LOCALINKEDSEREV
Output:
id
------------------------
DROP TABLE dbo.CocoJambo

Related

No result rowset is associated with the execution of this query

I am creating an Execute SQL task in SSIS 2016 which calls an insert stored procedure. I am trying to return the id of the newly created row in the output parameter but facing the following error.
No result rowset is associated with the execution of this query
I had set the SQL Server Profiler on to see what was generated and it was as follows
declare #p4 int
set #p4=NULL
exec sp_executesql N'Exec [dbo].[InsertPkgAudit] #P1,#P2',N'#P1 varchar(16),#P2 int OUTPUT','CoreReferenceETL',#p4 output
select #p4
If I execute the following it manually it works
DECLARE #auditId INT;
EXEC [dbo].[InsertPkgAudit] #packageName = 'CoreReferenceETL', #auditId = #auditId OUTPUT;
PRINT #auditId;
So it is clear that the stored procedure is fine but some problem with the way its called in SSIS. Could somebody help ?
The Execute SQL task contains the following statement
Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ?
The parameter mapping is as follows
The result pane is as follows
The stored procedure is as follows:
CREATE Procedure [dbo].[InsertPkgAudit]
#packageName varchar(100),
#auditId int output
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[PkgAudit] ([PackageName], [StartTime])
VALUES (#packageName, GETDATE());
SET #auditId = SCOPE_IDENTITY();
END
The table structure is as follows
You have told SSIS that your procedure returns a result set. But it doesn't. It populates an OUTPUT parameter instead.
You can either change your proc to return a resultset, or you can modify the Execute task and
Specify No Result Set
Change the query to this:
`Exec [dbo].[InsertPkgAudit] #packageName =?, #auditId = ? OUTPUT`
I just had a similar issue and while looking for some sort of solution I came across this old post. I wasn't able to find the solution online but, here is how I resolved my issue. I hope this helps folks in the future.
If you really need to get the data passed via RowSet, you will need to select as
'ColumnName'.
Declare #fname varchar(50)
Declare #lname varchar(50)
set #fname ='John'
set #lname= 'Doe'
select #fname, #lname--without column name
select #fname as 'firstName', #lname as 'LastName'--with column name
Here is how they would show up in the results.
You can now map the result to proper variable.

SQL Server 2012 dynamic SQL - stored procedure - getting syntax error

I am writing scripts to generate stored procedures within a database whose current schema notation will be unknown (think shared hosting).
I have decided to use dynamic SQL within the stored procedures so that the web application can pass the database schema based on a user defined setting to the SQL Server in order for it to fire properly.
When I started writing the stored procedures, I noticed that dynamic SQL opens up a whole SQL injection problem I would not normally have so I re-wrote the procedure to combat this. However even though SQL allows me to run the script to generate the stored procedure, each time I try to run the test stored procedure, I get a syntax error
Incorrect syntax near the keyword 'WHERE'
I believe this is to do with the parameter for the schema but I am at a loss as to why this is not working? I am entering the value dbo for the schema.
/*
Name : usp_GetTestTicker
Description : returns test ticker
*/
if not exists (select * from dbo.sysobjects
where id = object_id(N'usp_GetTestTicker')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
BEGIN
DECLARE #sql as nvarchar(150)
SET #sql = 'CREATE procedure usp_GetTestTicker AS'
EXEC(#sql)
END
GO
ALTER PROCEDURE usp_GetTestTicker
#schema VARCHAR(25),
#TickerItemId INT
AS
SET NOCOUNT ON
BEGIN
DECLARE #sql_cmd NVARCHAR(MAX)
DECLARE #sql_params NVARCHAR(MAX)
SET #sql_cmd = N'SELECT * FROM #schema.TickerItem WHERE TickerItemId = #TickerItemId'
SET #sql_params = N'#schema VARCHAR(25), #TickerItemId INT'
EXEC sp_executesql #sql_cmd, #sql_params, #schema, #TickerItemId
END
GO
To prevent SQL injection, you will need to validate the schema against the sys.schemas table, e.g.
ALTER PROCEDURE usp_GetTestTicker
#schema NVARCHAR(25),
#TickerItemId INT
AS
BEGIN
SET NOCOUNT ON
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = #schema)
BEGIN
-- throw an error here. Your web code will have to handle the error and report an invalid schema
END
ELSE
BEGIN
DECLARE #sql_cmd NVARCHAR(MAX), #sql_params NVARCHAR(MAX)
SET #sql_cmd = N'SELECT * FROM ' + #schema + '.TickerItem WHERE TickerItemId = #TickerItemId'
SET #sql_params = N'#TickerItemId INT'
EXEC sp_executesql #sql_cmd, #sql_params, #TickerItemId
END
END

Call SQL linked sever function or stored procedure from select statement

I have a stored procedure which calls a lookup function as part of the SELECT statement:
-- PX type
CASE WHEN coi.SKU_ID like 'PX%' THEN
[GG].dbo.PXStockInventoryLookup(coi.SKU_ID)
ELSE
0
END
In the production environment, the GG database is on a different server so a linked server is used to reference it. Trying to call the function using 4 part naming gives this error:
Remote function reference 'UATLINK.GG.dbo.PXStockInventoryLookup' is not allowed, and the column name 'UATLINK' could not be found or is ambiguous.
After some research I found out about using Dynamic SQL, OPENQUERY and sp_executesql in a local function:
DECLARE #ParamDefinition as nvarchar(100)
SET #ParamDefinition = N'#Result int output'
DECLARE #sql nvarchar(4000);
SET #sql = 'SELECT * FROM OPENQUERY( [UATLINK], ''SELECT [GG].[dbo].[PXStockInventoryLookup](''''' + #param + ''''')'')'
exec sp_executesql #sql, #ParamDefinition, #Result = #sii output
return #sii
This code works fine in isolation, but I can't create it a function as SQL doesn't allow me to call a function from within another function. I can create is as a stored procedure but then I can't call it from the select statement!
I'm just going round in circles trying to solve this, any ideas?

SQL Server / Create view from stored procedure

I am trying to create a view out of a stored procedure and am perplexed to see two opposing results from a very similar approach.
Example 1
CREATE PROCEDURE cv AS
GO
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
Whereas this example creates the view once the procedure is created for the 1st time, it will not recreate the view when I execute the procedure at a later stage using:
EXEC cv
Example 2
CREATE PROCEDURE cv
#table SYSNAME
AS
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW '+ #table +' AS SELECT * FROM someOtherTable'
This one instead does not create the view when the procedure is created for the first time but creates the view afterwards every time it is called by:
EXEC #sql;
Why is this the case? I think this is really confusing and does not make sense or does it?
For your 1st statement
CREATE PROCEDURE cv AS
GO --<-- This GO here terminates the batch
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
the GO batch terminator create the procedure and the EXECUTES the following statement straightaway. So it appears to you as you have created a procedure which created the view for you.
Infact these are two statements in two batches.
--BATCH 1
CREATE PROCEDURE cv AS
GO
--BATCH 2
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
Batch 1 Creates a procedure which has nothing inside it, but it creates a procedure object for you with no functionality/Definition at all.
Statement after the key word GO is executed separately and creates the view for you.
My Suggestion
Always check for an object's existence before you create it. I would write the procedure something like this..
CREATE PROCEDURE cv
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID ('test', 'V') IS NOT NULL
BEGIN
DROP VIEW test
END
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
END
In Example 1 - you are creating a view with a hard-coded name of test. On subsequent runs of your proc, as the view already exists, SQL Server will throw an error because you are trying to create a view with the same name as one that already exists.
In Example 2, you are passing in the name of the view as a parameter. This will always create a new view unless the #table value you pass in corresponds to an existing view.
Just wondering - why are you creating a view with a stored proc? This is not something you would normally do in SQL.
You need to change
EXEC #sql to EXEC (sql)
EXEC can be use to run stored procedure, not dynamic sql
eg.
declare #dd varchar(100)='Select ''A'''
exec (#dd) ->will work fine
exec #dd -> Error
Read more about The Curse and Blessings of Dynamic SQL
Create view statement cannot be used with a stored procedure
EXEC ('CREATE VIEW ViewName AS SELECT * FROM OPENQUERY(Yourservername,''EXECUTE [databasename].[dbo].[sp_name] ''''' +Parameter + ''''''')')

SQL Server Stored Procedure Parameter

I am trying to create a stored procedure with one parameter. I want the stored procedure to perform an update query and the parameter that I pass when it executes is the table that should be updated. I have been unsuccessful with creating the procedure with the parameter.
CREATE PROCEDURE cleanq7 #tablename varchar(100)
AS
BEGIN
UPDATE #tablename
SET IMPOSSIBLE_CASE = '1'
WHERE q7='1'
GO
The message I receive when I run this is:
Msg 102, Level 15, State 1, Procedure cleanq7, Line 6
Incorrect syntax near '1'.
I tried just the indented update query on a table in test database and it functioned as expected, so I imagine this is an issue with my syntax for declaring the stored procedure.
Any help would be greatly appreciated!
CREATE PROCEDURE cleanq7
#tablename NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'UPDATE ' + QUOTENAME(#tablename) +
N' SET IMPOSSIBLE_CASE = ''1''
WHERE q7 = ''1'''
EXECUTE sp_executesql #Sql
END
GO
Since you are passing the table name you will need to build your UPDATE statement dynamically and then Execute it using system stored procedure sp_executesql.
When you pass the table name as a String Sql Server treats it as a string not as an Object name. Using QUOTENAME() function puts square brackets [] around the passed table name and then sql server treats it as an object name.
QuoteName function also protects you against Sql injection attack.

Resources