web-dev-qa-db-fra.com

Comment passer une table temporaire en tant que paramètre dans une procédure stockée distincte

J'ai une procédure stockée qui prend un paramètre d'entrée @CategoryKeys varchar, et analyse son contenu dans une table temporaire, #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

Si la table temporaire a des lignes, je voudrais passer la table dans une procédure stockée distincte. Comment pourrais-je créer un paramètre dans la procédure séparée pour contenir la table temporaire?

30
bsivel

Lorsque vous créez une table #TEMP, la "portée" est plus grande que la procédure dans laquelle elle est créée.

Voici un exemple:

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

AYANT DIT QUE, S'IL VOUS PLAÎT, NE PAS ENCODER BEAUCOUP DE CELLES-CI. SON ÉQUIVALENT SQL D'UNE VARIABLE MONDIALE ET IL IS DIFFICILE À MAINTENIR ET À BUG PRONE.

14
granadaCoder

Bien que la compréhension de la portée réponde au besoin direct, nous avons pensé qu'il pourrait être utile d'ajouter quelques options supplémentaires au mélange pour élaborer les suggestions des commentaires.

  1. Passer XML dans la procédure stockée
  2. Passer un paramètre table dans la procédure stockée

1. Passez XML dans la procédure stockée

Avec XML passé dans un paramètre, vous pouvez utiliser le XML directement dans vos requêtes SQL et rejoindre/appliquer à d'autres tables:

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

Ensuite, un appel à la procédure stockée pour tester:

DECLARE @Text XML = '<keys><key>1</key><key>2</key></keys>'
EXEC sp_PassXml @Text

Exemple de sortie d'une requête simple.

Key
-----------
1
2

2. Passez un paramètre table dans la procédure stockée

Tout d'abord, vous devez définir le type défini par l'utilisateur pour la variable de table à utiliser par la procédure stockée.

CREATE TYPE KeyTable AS TABLE ([Key] INT)

Ensuite, vous pouvez utiliser ce type comme paramètre pour le proc stocké (le READONLY est requis car seul IN est pris en charge et le tableau ne peut pas être modifié)

CREATE PROC sp_PassTable
    @Keys KeyTable READONLY
AS
BEGIN
    SET NOCOUNT ON
    SELECT * FROM @Keys
END
GO

Le proc stocké peut ensuite être appelé avec une variable de table directement à partir de SQL.

DECLARE @Keys KeyTable
INSERT @Keys VALUES (1), (2)
EXEC sp_PassTable @Keys

Remarque: Si vous utilisez .NET, vous pouvez transmettre le paramètre SQL à partir d'un type DataTable correspondant au type défini par l'utilisateur.

Exemple de sortie de la requête:

Key
-----------
1
2
25
Jason W