Parâmetro com valor de tabela como parâmetro de saída para procedimento armazenado

33

É possível que o parâmetro com valor de tabela seja usado como parâmetro de saída para o procedimento armazenado?

Aqui está o que eu quero fazer no código

/*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
adotante
fonte

Respostas:

35

Não, infelizmente, os parâmetros do valor da tabela são somente leitura e somente entrada. Este tópico em geral é abordado muito bem em Como compartilhar dados entre procedimentos armazenados , que apresenta todas as alternativas. Minha recomendação seria usar uma #temptabela.

Remus Rusanu
fonte
1

Esta é uma publicação mais antiga, mas estava próxima do topo quando eu estava pesquisando "Parâmetro com valor de tabela como parâmetro de saída para procedimento armazenado". Embora eu entenda que você não pode passar um parâmetro com valor de tabela como parâmetro de saída, eu imagino que o objetivo é usar esse parâmetro de saída com valor de tabela como parâmetro de entrada com valor de tabela em outro procedimento. Vou mostrar um exemplo de como eu fiz esse trabalho.

Primeiro, crie alguns dados para trabalhar:

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'   )
;

Em seguida, crie um procedimento armazenado para capturar alguns dos dados. Normalmente, é nesse local que você está tentando criar um parâmetro de saída com valor de tabela.

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

Além disso, você desejará criar um tipo de dados (tipo de tabela) em que os dados do primeiro procedimento armazenado possam ser passados ​​como o parâmetro de entrada para o próximo procedimento armazenado.

create type tblType as Table (id int)

Em seguida, crie o segundo procedimento armazenado que aceitará o parâmetro com valor de tabela.

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

Concedido, esse não é um verdadeiro parâmetro de saída com valor de tabela, mas provavelmente produzirá resultados semelhantes aos que você procuraria. Declare seu parâmetro com valor de tabela, preencha-o com dados executando o procedimento armazenado nele e use-o como a variável de entrada para o próximo procedimento.

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

além da resposta bem feita por remus, incluindo o link que ele forneceu

Como compartilhar dados entre procedimentos armazenados

há situações em que você recebe as seguintes mensagens de erro ao salvar os resultados de um procedimento armazenado em uma tabela:

Uma instrução INSERT EXEC não pode ser aninhada.

A transação atual não pode ser confirmada e não pode suportar operações que gravam no arquivo de log. Reverter a transação

e quando isso acontece nos meus próprios procedimentos armazenados que desenvolvo para meu próprio uso

por exemplo, uma ferramenta para me informar sobre logintodos os grupos do AD aos quais pertence e todas as suas permissões em todos os bancos de dados em um servidor

Crio uma tabela temporária fora do procedimento e passo seu nome como parâmetro

--===============
-- 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

e dentro do procedimento, depois de todos os cálculos, quando estou retornando os dados finais (abaixo de um exemplo), verifico se estamos produzindo para uma tabela ou apenas voltando para a tela e crio o script dinamicamente.

            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)

Depois disso, você terá as informações necessárias na tela ou se tiver passado uma tabela temporária como parâmetro, eles terão os dados agora.

essa é uma solução que encontrei, mas a uso apenas para meus próprios trabalhos, DBAcaso contrário, isso será considerado de alto risco para a injeção de sql .

Marcello Miorelli
fonte