web-dev-qa-db-fra.com

Paramètre table comme paramètre de sortie pour la procédure stockée

Est-il possible d'utiliser le paramètre Table-Valued comme paramètre de sortie pour la procédure stockée?

Voici ce que je veux faire en code

/*First I create MY type */
CREATE TYPE typ_test AS TABLE 
(
     id int not null
    ,name varchar(50) not null
    ,value varchar(50) not null
    PRIMARY KEY (id)
)
GO


--Now I want to create stored procedu whic is going to send output type I created, 
--But it looks like it is inpossible, at least in SQL2008
create  PROCEDURE [dbo].sp_test
         @od datetime 
        ,@do datetime 
        ,@poruka varchar(Max) output
        ,@iznos money output 
        ,@racun_stavke  dbo.typ_test   READONLY --Can I Change READONLY with OUTPUT ?
AS
BEGIN
    SET NOCOUNT ON;

    /*FILL MY OUTPUT PARAMS AS I LIKE */


    end
33
adopilot

Non, malheureusement, les paramètres de valeur de table sont en lecture seule et en entrée uniquement. Ce sujet en général est très bien couvert dans Comment partager des données entre des procédures stockées , qui présente toutes les alternatives. Ma recommandation serait d'utiliser un #temp table.

36
Remus Rusanu

Il s'agit d'un article plus ancien, mais il était proche du sommet lorsque je recherchais "Paramètre de valeur de table comme paramètre de sortie pour la procédure stockée". Bien que je comprenne que vous ne pouvez pas passer un paramètre de valeur de table en tant que paramètre de sortie, j'imagine que le but est d'utiliser ce paramètre de sortie de valeur de table comme paramètre d'entrée de valeur de table dans une autre procédure. Je vais montrer un exemple de la façon dont j'ai fait ce travail.

Tout d'abord, créez des données avec lesquelles travailler:

create table tbl1
(
id int,
fname varchar(10),
gender varchar(10)
);
create table tbl2
(
id int,
lname varchar(10)
);
insert into tbl1
values
(1,'bob'  ,'m'),
(2,'tom'  ,'m'),
(3,'sally','f')
;
insert into tbl2
values
(1,'jones'   ),
(2,'johnson' ),
(3,'smith'   )
;

Ensuite, créez une procédure stockée pour capturer certaines des données. Normalement, c'est là que vous essayez de créer un paramètre de sortie table.

create procedure usp_OUTPUT1
 @gender varchar(10)
as
Begin
    select id from tbl1 where gender = @gender
End

En outre, vous souhaiterez créer un type de données (type de table) où les données de la première procédure stockée peuvent être passées en tant que paramètre d'entrée pour la procédure stockée suivante.

create type tblType as Table (id int)

Ensuite, créez la deuxième procédure stockée qui acceptera le paramètre table.

create procedure usp_OUTPUT2
@tblType tblType readonly  --referencing the type created and specify readonly
as
begin
 select lname from tbl2 where id in (select id from @tblType)
end

Certes, ce n'est pas un véritable paramètre de sortie de valeur table, mais il produira probablement des résultats similaires à ceux que vous recherchez. Déclarez votre paramètre table, remplissez-le de données en y exécutant la procédure stockée, puis utilisez-le comme variable d'entrée pour la procédure suivante.

Declare @tblType tblType 
insert into @tblType execute usp_OUTPUT1 'm'
execute usp_OUTPUT2 @tblType
1
Andrew

en plus de la réponse joliment mise par remus y compris le lien qu'il a fourni

Comment partager des données entre des procédures stockées

il existe des situations où vous obtenez les messages d'erreur suivants lors de l'enregistrement des résultats d'une procédure stockée dans une table:

ne instruction INSERT EXEC ne peut pas être imbriquée.

La transaction en cours ne peut pas être validée et ne peut pas prendre en charge les opérations qui écrivent dans le fichier journal. Annulez la transaction

et lorsque cela se produit sur mes propres procédures stockées que je développe pour mon propre usage

par exemple un outil pour me dire à partir d'un login tous les groupes AD auxquels il appartient et toutes leurs autorisations dans toutes les bases de données d'un serveur

Je crée une table temporaire en dehors de la procédure et passe son nom en paramètre

--===============
-- this way below it works, by passing a temp table as a parameter
--===============

                if OBJECT_ID('tempdb.dbo.#my_table') IS NOT NULL
                   DROP TABLE #my_table

                CREATE TABLE #my_table(
                    db nvarchar(128)   COLLATE Latin1_General_CI_AS  NULL,
                   permission_type nvarchar(128)   COLLATE Latin1_General_CI_AS  NULL,
                    login_  nvarchar(128)   COLLATE Latin1_General_CI_AS  NULL,
                    role_  nvarchar(128)   COLLATE Latin1_General_CI_AS  NULL,
                    Obj    nvarchar(517)   COLLATE Latin1_General_CI_AS  NULL,
                    Permission nvarchar(128)   COLLATE Latin1_General_CI_AS  NULL,
                    script nvarchar(1008)  COLLATE Latin1_General_CI_AS  NULL
                ) 

                exec sp_GetLoginDBPermissionsX 
                    @Login='my_loginname', 
                    @debug=0,
                    @where_to_save ='#my_table'

                select *
                from #my_table

et à l'intérieur de la procédure, après tous les calculs, lorsque je retourne les données finales (ci-dessous un exemple), je vérifie si nous sortons dans une table ou juste de retour à l'écran et créons le script dynamiquement.

            select @sql = case when @where_to_save IS not null then 
            '
            insert into ' + @where_to_save + '(db,Permission_Type,login_,role_,obj,Permission,script) '
            else '' end + 
'
        SELECT 
            J.db,
            J.Permission_Type,
            J.login_,
            J.role_,
            J.Obj,
            J.Permission,
            J.script
        FROM #tablewithpermissions J
        WHERE J.login_ IN ( SELECT  L1.LOGIN_FROM COLLATE Latin1_General_CI_AS FROM #logins L1)
           OR J.role_ IN  ( SELECT  L1.LOGIN_FROM COLLATE Latin1_General_CI_AS FROM #logins L1)
       ORDER BY J.DB, J.[permission_order]
'
        --print(@sql)

        EXEC(@SQL)

Après cela, vous avez soit les informations dont vous avez besoin à l'écran, ou si vous avez passé une table temporaire en tant que paramètre, elle aura les données maintenant.

c'est une solution que j'ai trouvée, mais je ne l'utilise que pour mes propres travaux DBA sinon cela sera considéré comme à haut risque pour Sql Injection .

1