Parámetro con valores de tabla como parámetro de salida para el procedimiento almacenado

33

¿Es posible utilizar el parámetro con valores de tabla como parámetro de salida para el procedimiento almacenado?

Aquí está lo que quiero hacer en 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
adopilot
fuente

Respuestas:

35

No, desafortunadamente los parámetros del valor de la tabla son de solo lectura y solo de entrada. Este tema en general se trata muy bien en Cómo compartir datos entre procedimientos almacenados , que presenta todas las alternativas. Mi recomendación sería usar una #tempmesa.

Remus Rusanu
fuente
1

Esta es una publicación anterior, pero estaba cerca de la parte superior cuando buscaba "Parámetro con valores de tabla como parámetro de salida para el procedimiento almacenado". Si bien entiendo que no puede pasar un parámetro con valores de tabla como un parámetro de salida, me imagino que el objetivo es utilizar ese parámetro de salida con valores de tabla como un parámetro de entrada con valores de tabla en otro procedimiento. Mostraré un ejemplo de cómo hice que esto funcionara.

Primero, cree algunos datos para trabajar con:

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

A continuación, cree un procedimiento almacenado para capturar algunos de los datos. Normalmente, aquí sería donde está intentando crear un parámetro de salida con valores de tabla.

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

Además, querrá crear un tipo de datos (tipo de tabla) donde los datos del primer procedimiento almacenado se puedan pasar como parámetro de entrada para el siguiente procedimiento almacenado.

create type tblType as Table (id int)

A continuación, cree el segundo procedimiento almacenado que aceptará el parámetro con valores de tabla.

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

Por supuesto, este no es un verdadero parámetro de salida con valores de tabla, pero es probable que produzca resultados similares a los que estaría buscando. Declare su parámetro con valores de tabla, complételo con datos ejecutando el procedimiento almacenado en él, luego úselo como la variable de entrada para el siguiente procedimiento.

Declare @tblType tblType 
insert into @tblType execute usp_OUTPUT1 'm'
execute usp_OUTPUT2 @tblType
Andrés
fuente
1

Además de la respuesta bien puesta por Remus, incluido el enlace que proporcionó

Cómo compartir datos entre procedimientos almacenados

Hay situaciones en las que obtiene los siguientes mensajes de error al guardar los resultados de un procedimiento almacenado en una tabla:

Una instrucción INSERT EXEC no se puede anidar.

La transacción actual no se puede confirmar y no puede admitir operaciones que escriben en el archivo de registro. Revertir la transacción

y cuando esto sucede en mis propios procedimientos almacenados que desarrollo para mi propio uso

por ejemplo, una herramienta para distinguirme de logintodos los grupos de AD a los que pertenece y todos sus permisos en todas las bases de datos en un servidor

Creo una tabla temporal fuera del procedimiento y paso su nombre 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

y dentro del procedimiento, después de todos los cálculos, cuando devuelvo los datos finales (debajo de un ejemplo) verifico si estamos enviando a una tabla o simplemente de regreso a la pantalla y creo el script dinámicamente.

            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)

Después de eso, tiene la información que necesita en la pantalla, o si ha pasado una tabla temporal como parámetro, tendrá los datos ahora.

Esta es una solución que encontré, pero solo la uso para mis propios trabajos, de lo DBAcontrario, esto se considerará de alto riesgo para la inyección de SQL .

Marcello Miorelli
fuente