How to use openxml in a custom function in SQL Server

I have an XML structure that I am parsing using OPENXML

in a stored procedure to retrieve the parameters used to make a request. This procedure was a basic procedure calling another stored procedure (procedure 2). Procedure 2 uses insert-exec to retrieve data from the underlying procedure. This works great as long as we only call procedure 2 or the base procedure.

My first problem is that I have another procedure (procedure 3) that should now get the result from procedure 2 (I need the business rules this procedure enforces), but cannot because of the message:

INSERT EXEC statement cannot be nested.

Then I tried to follow the basic procedure and make it a table function, but when I followed it, I get the message:

Only functions and some extended stored procedures can be executed within a function.

How do you get around one or both of these problems?

EDIT 1 I am including a code snippet to show the basic procedure (Procedure 1) and the procedure for fulfilling the business requirements resulting from this procedure (Procedure 2). If there is a 3rd procedure that needs results using business rules, we run into problems.

create procedure dbo.p_Proc
  @Xml xml
as
begin
  set nocount on;

  declare @l_idoc int
      , @InfoId int
      , @InfoTypeId int
      , @Id int
      , @Name varchar(50)
      , @StatusId int
      , @RoleId int
      , @XmlBase xml
      , @l_path varchar(100);

  declare @T_TABLE table(
        InfoId int
      , InfoTypeId int
  );

  declare @T_RESULT table
  (
      Field1 int
    , Field2 varchar(50)
    , Field3 int
  );

  EXEC sp_xml_preparedocument @l_idoc OUTPUT, @Xml;

  set @l_path = '/xml/Info';        
  insert into @T_TABLE(InfoId, InfoTypeId)
  select InfoId, InfoTypeId
  from  OPENXML (@l_idoc, @l_path, 1)
      with (
         InfoId int './@InfoId'
         , InfoTypeId int './@InfoTypeId'
      );

  select @InfoId = InfoId
     , @InfoTypeId = InfoTypeId
    from @T_TABLE;

  -- create the XML to call the base widgets
  select @XmlBase = 
  (
    select *
      from
    (
      select t.Id, t.Name, t.StatusId, t.RoleId
        from @T_TABLE w
      inner join dbo.T_TABLE2 t
        on t.InfoId = w.InfoId
         and t.InfoTypeId = w.InfoTypeId
    ) b
    for xml raw('Widget'), root('Xml')
  );

  -- retrieve widgets from base security
  insert into @T_RESULT(Field1, Field2, Field3)
  exec dbo.p_ProcBase @Xml = @XmlBase;

  -- apply business logic here


  select w.Field1, w.Field2, w.Field3
    from @T_RESULT w;
end;
go

create procedure dbo.p_ProcBase
  @Xml xml = null
as
begin
  set nocount on;

  declare @l_idoc int
      , @Id int
      , @Name varchar(50)
      , @StatusId int
      , @RoleId int
      , @l_path varchar(100);

  declare @T_Table table(
        Id int
      , Name varchar(50)
      , StatusId int
      , RoleId int
  );

  EXEC sp_xml_preparedocument @l_idoc OUTPUT, @Xml;

  set @l_path = '/Xml/Widget';      
  insert into @T_Table(Id, Name, StatusId, RoleId)
  select Id, Name, StatusId, RoleId
  from  OPENXML (@l_idoc, @l_path, 1)
      with (
         ProjectId int './@Id'
         , WidgetTypeName varchar(50) './@Name'
         , WorkflowStatusId int './@StatusId'
         , UserRoleId bigint './@RoleId'
      );

  select @Id = w.Id
     , @Name = w.Name
     , @StatusId = w.StatusId
     , @RoleId = w.RoleId
    from @T_Table w;

  -- retrieve enabled widgets for which the user has a role in the current workflow state
  select t.Field1, t.Field2, t.Field3
    from dbo.T_TABLE t
   where t.StatusId = @StatusId
     and t.RoleId = @RoleId;
end;

      

+3


source to share


1 answer


To send a dataset (table) between procs, you must use the table type, store the proc2 result in a table type variable, and add only the read-only table type to proc3

First you have to create a table type to map the output to proc2:

CREATE TYPE T_RESULT AS TABLE
(
      Field1 int
    , Field2 varchar(50)
    , Field3 int
  );

      

In dbo.p_Proc

change @T_RESULT

to:



declare @T_RESULT T_RESULT

      

Then create proc3:

CREATE PROCEDURE dbo.proc3
    @T_RESULT T_RESULT READONLY
AS 
BEGIN    
    SET NOCOUNT ON
    INSERT INTO T3(...) 
    SELECT ... FROM @T_RESULT 
END

      

Don't forget to add READONLY after the table type parameter in proc.

+2


source







All Articles