How can I provide parameter values to a Stored Proc called by a Stored Proc (SQL Server)?

守給你的承諾、 提交于 2019-12-25 18:25:10

问题


Based on the answer here, I've got a start on a test SP that I plan to eventually build up to call several times, with more temp tables and different values for the "Unit" parameter. The @BegDate, @EndDate, and @SortBy params will always be the same, though - those provided by the user.

This is what I have so far:

IF OBJECT_ID ( 'testSP', 'P' ) IS NOT NULL   
    DROP PROCEDURE testSP;  
GO
CREATE PROC [dbo].[testSP]
    @BegDate datetime,
    @EndDate datetime,
    @SortBy varchar(20)
AS
BEGIN
    SELECT * FROM sys.databases
END
GO
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC SP2BCalled @Unit = "FirstUnit"; @BegDate = @BegDate;  @EndDate = @EndDate; @SortBy = @SortBy; ')

SELECT * FROM #MyTempTable

My question: Is this the right way to pass params to the existing Stored Procedure (SP2BCalled):

'EXEC SP2BCalled @Unit = "Abuelos"; @BegDate = @BegDate;  @EndDate = @EndDate; @SortBy = @SortBy; ')

IOW, the SP being called requires @BegDate, @EndDate, and @SortBy parameters to be passed to it, so the new SP gathers those to pass on, but what is the correct syntax for doing so?

Should I do it like this instead:

CREATE PROC [dbo].[testSP]
    @BegDateLocal datetime,
    @EndDateLocal datetime,
    @SortByLocal varchar(20)

...and then call the existing SP like so:

SELECT * INTO #MyTempTable1 FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC SP2BCalled @Unit = "FirstUnit"; @BegDate = @BegDateLocal;  @EndDate = @EndDateLocal; @SortBy = @SortByLocal; ')

SELECT * INTO #MyTempTable2 FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC SP2BCalled @Unit = "SecondUnit"; @BegDate = @BegDateLocal;  @EndDate = @EndDateLocal; @SortBy = @SortByLocal; ')

SELECT * INTO #MyTempTable3 FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC SP2BCalled @Unit = "ThirdUnit"; @BegDate = @BegDateLocal;  @EndDate = @EndDateLocal; @SortBy = @SortByLocal; ')

...?, or how?

I will then need to UNION all the temp tables (#MyTempTable1, #MyTempTable2, and #MyTempTable3) and return that as the final result.

UPDATE

Heinrich Smit is right; when I tried to run the testSP, I got:

Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install. Configuration option 'Ad Hoc Distributed Queries' changed from 0 to 1. Run the RECONFIGURE statement to install. OLE DB provider "SQLNCLI11" for linked server "(null)" returned message "Login timeout expired". OLE DB provider "SQLNCLI11" for linked server "(null)" returned message "A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online.".


回答1:


It doesn't matter whether the local parameters are the same name as the parameters of the procedure to be called or not. So there is no difference between the two ways you are asking about doing it.

What does matter is that you should not separate the parameters with semi-colons. You should use commas.

'EXEC SP2BCalled @Unit = ''FirstUnit'', @BegDate = @BegDateLocal,  @EndDate = @EndDateLocal, @SortBy = @SortByLocal, ')



回答2:


If you know what the structure of the dataset being returned is, then you can use something like the following:

--  Making assumptions about the data set
CREATE TABLE #MyTempTable1
 (
   Col1    int            not null
  ,Col2    datetime       not null
  ,ColEtc  nvarchar(max)  not null
 )

INSERT #MyTempTable1 (Col1, Col2, ColEtc)
 EXECUTE SP2BCalled
   @Unit    = 'Abuelos'
  ,@BegDate = @BegDate
  ,@EndDate = @EndDate
  ,@SortBy  = @SortBy



回答3:


OPENROWSET only accepts a literal string. To use it you would need to build the whole command in dynamic SQL and then exec that command.

Temp tables created inside an exec only exist in the scope of the exec - they disappear when it returns.

You can use global temp tables ##MyTempTable1 etc, but if multiple users are calling this at the same time, they will all be writing into the same global temp table.
The NEWID trick makes a unique global temp table to avoid this, but is harder to manage.

Using a double quote " only works if SET QUOTED_IDENTIFIER is OFF on the remote server. If it is ON, then anything in double quotes is not treated as a string. Instead it is treated as an object name like a column or a table. To avoid worrying about this, use a pair of single quotes '' to represent a single quote inside a string. However, it does become mind boggling to handle nested quotes that way.

You only need to configure the remote server to accept ad-hoc distributed queries once, so you can do it up front, rather than on each call.

stackoverflow is the name of the database holding the remote stored proc. Just substitute the correct name for you.

Declare @Unit varchar(max) = 'FirstUnit', @BegDateLocal datetime = '01-jun-2016', @EndDateLocal datetime = '30-jun-2016', @SortBy varchar(max) = 'X'
Declare @sql nvarchar(max)
Declare @exec nvarchar(max) = 'EXEC stackoverflow.dbo.SP2BCalled @Unit = ''''FirstUnit'''', @BegDate = ''''' + convert(varchar(max), @BegDateLocal, 120) + ''''''
     + ', @EndDate = ''''' + convert(varchar(max), @EndDateLocal, 120) + ''''''
     + ', @SortBy = ''''' + @SortBy + ''''''
Declare @GlobalTemp varchar(max) = '##MyTempTable1'
Declare @GlobalTempNEWID varchar(max) = '[##' + cast(newid() as char(36)) + ']'
Declare @DropCheck varchar(max) = 'IF object_id(''tempdb..' + @GlobalTemp + ''') is not null drop table ' + @GlobalTemp
Set @sql = @DropCheck + '; SELECT * INTO ' + @GlobalTemp 
            + 'FROM OPENROWSET(
               ''SQLNCLI'',
               ''Server=(local)\SQL2008;Trusted_Connection=yes;'',' 
               + '''' + @exec + ''')'

Print @sql
exec (@sql)
SELECT * FROM ##MyTempTable1



回答4:


As far as I know, you won' be able to directly pass the parameter into the OPENROWSET call. You would need to create a dynamic SQL string and execute it, e.g.

DECLARE @SQL VARCHAR(MAX)
SET @SQL = 'SELECT * FROM OPENROWSET(''SQLNCLI'', ''DRIVER={SQL Server}; Server=127.0.0.1;'',''EXEC [Test].[dbo].[Test] @var1 = ' + @var1 + ''')'
EXEC(@SQL)

Also, from the code provided, the

SELECT * INTO #MyTempTable FROM OPENROWSET(..

part will never run as part of the stored procedure, as there are multiple GO's that ends the definition.

You also aren't specifying the database to be used in OPENROWSET.

Is there a specific reason for using OPENROWSET, instead of using the FQDN of the linked server, [server].[database].[schema].[table]?



来源:https://stackoverflow.com/questions/37710416/how-can-i-provide-parameter-values-to-a-stored-proc-called-by-a-stored-proc-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!