Табличный параметр как выходной параметр для хранимой процедуры

33

Можно ли использовать параметр Table-Valued в качестве выходного параметра для хранимой процедуры?

Вот что я хочу сделать в коде

/*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
источник

Ответы:

35

Нет, к сожалению, параметры табличных значений доступны только для чтения и только для ввода. Эта тема в целом очень хорошо освещена в разделе Как обмениваться данными между хранимыми процедурами , в котором представлены все альтернативы. Моя рекомендация будет использовать #tempтаблицу.

Ремус Русану
источник
1

Это старый пост, но он был в самом верху, когда я искал «Табличный параметр как выходной параметр для хранимой процедуры». Хотя я понимаю, что вы не можете передать табличный параметр в качестве выходного параметра, я хотел бы представить, что целью является использование этого табличного выходного параметра в качестве табличного входного параметра в другой процедуре. Я покажу пример того, как я сделал эту работу.

Сначала создайте некоторые данные для работы с:

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

Затем создайте хранимую процедуру для сбора некоторых данных. Обычно это то место, где вы пытаетесь создать табличный выходной параметр.

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

Кроме того, вы захотите создать тип данных (тип таблицы), в котором данные из первой хранимой процедуры могут быть переданы в качестве входного параметра для следующей хранимой процедуры.

create type tblType as Table (id int)

Затем создайте вторую хранимую процедуру, которая будет принимать табличный параметр.

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

Конечно, это не истинный табличный выходной параметр, но он, скорее всего, даст результаты, аналогичные тому, что вы искали. Объявите свой табличный параметр, заполните его данными, выполнив в нем хранимую процедуру, а затем используйте его в качестве входной переменной для следующей процедуры.

Declare @tblType tblType 
insert into @tblType execute usp_OUTPUT1 'm'
execute usp_OUTPUT2 @tblType
Эндрю
источник
1

в дополнение к красиво поставленному ответу remus включая ссылку, которую он предоставил

Как обмениваться данными между хранимыми процедурами

Есть ситуации, когда вы получаете следующие сообщения об ошибках при сохранении результатов хранимой процедуры в таблице:

Оператор INSERT EXEC не может быть вложенным.

Текущая транзакция не может быть зафиксирована и не может поддерживать операции записи в файл журнала. Откат транзакции

и когда это происходит на моих собственных хранимых процедурах, которые я разрабатываю для собственного использования

например, инструмент, чтобы сказать мне из loginвсех групп AD, к которым он принадлежит, и все их разрешения во всех базах данных на сервере

Я создаю временную таблицу вне процедуры и передаю ее имя в качестве параметра

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

и внутри процедуры, после всех вычислений, когда я возвращаю окончательные данные (ниже примера), я проверяю, выводим ли мы в таблицу или просто обратно на экран, и динамически создаем сценарий.

            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)

После этого у вас появится информация, которая вам нужна, или если вы передали временную таблицу в качестве параметра, она будет иметь данные.

это одно решение, которое я нашел, но я использую его только для своих собственных работ, DBAиначе это будет считаться высоким риском для инъекций Sql .

Марчелло Миорелли
источник