如何将临时表作为参数传递到单独的存储过程中

bsi*_*vel 32 sql sql-server stored-procedures

我有一个存储过程,它接受一个输入参数@CategoryKeys varchar,并将其内容解析为临时表,#CategoryKeys.

        -- create the needed temp table.
        CREATE TABLE #CategoryKeys
          (
             CategoryKey SMALLINT
          );

        -- fill the temp table if necessary
        IF Len(rtrim(ltrim(@CategoryKeys))) > 0
          BEGIN
              INSERT INTO #CategoryKeys
                          (CategoryKey)
              SELECT value
              FROM   dbo.String_To_SmallInt_Table(@CategoryKeys, ',');
          END
Run Code Online (Sandbox Code Playgroud)

如果临时表有行,我想将表传递给一个单独的存储过程.我如何在单独的过程中创建一个参数来保存临时表?

Jas*_*n W 25

虽然理解范围界定了直接需求,但认为在混合中添加更多选项以阐述评论中的建议可能是有用的.

  1. 将XML传递给存储过程
  2. 将表值参数传递给存储过程

1.将XML传递给存储过程

将XML传递给参数后,您可以直接在SQL查询中使用XML并加入/应用于其他表:

CREATE PROC sp_PassXml
    @Xml XML
AS
BEGIN
    SET NOCOUNT ON
    SELECT T.Node.value('.', 'int') AS [Key]
    FROM @Xml.nodes('/keys/key') T (Node)
END
GO
Run Code Online (Sandbox Code Playgroud)

然后调用存储过程进行测试:

DECLARE @Text XML = '<keys><key>1</key><key>2</key></keys>'
EXEC sp_PassXml @Text
Run Code Online (Sandbox Code Playgroud)

简单查询的示例输出.

Key
-----------
1
2
Run Code Online (Sandbox Code Playgroud)

2.将表值参数传递给存储过程

首先,您必须为存储过程使用的表变量定义用户定义的类型.

CREATE TYPE KeyTable AS TABLE ([Key] INT)
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用该类型作为存储过程的参数(这READONLY是必需的,因为只IN支持并且表不能更改)

CREATE PROC sp_PassTable
    @Keys KeyTable READONLY
AS
BEGIN
    SET NOCOUNT ON
    SELECT * FROM @Keys
END
GO
Run Code Online (Sandbox Code Playgroud)

然后可以直接从SQL使用表变量调用存储过程.

DECLARE @Keys KeyTable
INSERT @Keys VALUES (1), (2)
EXEC sp_PassTable @Keys
Run Code Online (Sandbox Code Playgroud)

注意:如果您使用的是.NET,则可以从与用户定义的类型匹配的DataTable类型传递SQL参数.

查询的示例输出:

Key
-----------
1
2
Run Code Online (Sandbox Code Playgroud)

  • 虽然我已经接受了这个问题的答案,但我赞成这一点,因为"仅仅因为范围有效".....并不意味着它是一个很好的解决方案.像全局变量一样处理#tempTables是不好的常规做法.我这样做,我一直传递xml来促进基于集合的操作,以避免游标和RBAR. (3认同)

gra*_*der 14

创建#TEMP表时,"范围"大于其创建的过程.

以下是一个示例:

IF EXISTS 
    (
    SELECT * FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspProc002'  
    )
BEGIN
    DROP PROCEDURE [dbo].[uspProc002]
END


GO

CREATE Procedure dbo.uspProc002 
AS

BEGIN

/* Uncomment this code if you want to be more explicit about bad "wiring" */
/*
IF OBJECT_ID('tempdb..#TableOne') IS NULL
begin
        THROW 51000, 'The procedure expects a temp table named #TableOne to already exist.', 1;  
end
*/

    /* Note, I did not Create #TableOne in this procedure.  It "pre-existed".  An if check will ensure that it is there.  */
    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
        Insert into #TableOne ( SurrogateKey , NameOf ) select 2001, 'uspProc002'
    end

END


GO



IF EXISTS 
    (
    SELECT * FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspProc001'  
    )
BEGIN
    DROP PROCEDURE [dbo].[uspProc001]
END


GO

CREATE Procedure dbo.uspProc001 (
@Param1 int
)
AS

BEGIN


    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end


    CREATE TABLE #TableOne
    ( 
    SurrogateKey int , 
    NameOf varchar(12)
    )

    Insert into #TableOne ( SurrogateKey , NameOf ) select 1001, 'uspProc001'

    Select * from #TableOne

    EXEC dbo.uspProc002 

    Select * from #TableOne

    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end


END


GO




exec dbo.uspProc001 0
Run Code Online (Sandbox Code Playgroud)

如果说,请不要大量编写这些.它是全球变量的SQL等价物并且难以维持和破坏PRONE.