tsql - 如何在 SQL Server 中的用户定义函数中使用 openxml

标签 tsql sql-server-2005 sql-server-2008-r2 openxml

我有一个 XML 结构,我在存储过程中使用 OPENXML 对其进行解析,以检索用于执行查询的参数。该过程是另一个存储过程(过程 2)正在调用的基本过程。过程 2 使用 insert-exec 构造从基本过程获取数据。只要我们只调用过程 2 或基本过程,这种方法就非常有效。

我的第一个问题是,我有一个不同的过程(过程 3),现在需要从过程 2 获取结果(我需要此过程强制执行的业务规则),但由于以下消息而无法实现:

An INSERT EXEC statement cannot be nested.

然后,我尝试采用基本过程并将其设为表值函数,但是当我执行它时,我收到消息:

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

如何解决其中一个或两个问题?

编辑 1 我包含一个代码片段来显示基本过程(过程 1)以及对该过程的结果实现业务需求的过程(过程 2)。如果有第三个过程需要应用业务规则的结果,我们就会遇到问题。

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;

最佳答案

为了在proc之间发送数据集(表),必须使用Table类型,将proc2的输出存储在表类型的变量中,并向proc3添加只读表类型参数

首先,您必须创建一个表类型来映射 proc2 的输出:

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

dbo.p_Proc中将@T_RESULT更改为:

declare @T_RESULT T_RESULT

然后创建proc3:

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

不要忘记在过程中的表类型参数后面添加 READONLY。

关于tsql - 如何在 SQL Server 中的用户定义函数中使用 openxml,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30127547/

相关文章:

SQL Server 2005 动态选择

sql - 声明 VARBINARY 时使用变量指定 'size'

asp.net - SQL Server 2008 连接字符串问题

sql - 每天的数据差异

SQL获取不在列表中的项目

sql - 如何计算一段时间内每月的记录数

sql - 从日期时间中提取小时 (SQL Server 2005)

sql - 如何在mssql中将13位时间戳转换为日期和时间格式

sql - 我无法启用 sa 帐户