将变量添加到以XML作为参数的SQL Server存储过程

时间:2017-11-22 21:48:43

标签: sql-server xml stored-procedures

将XML传递给存储过程时可以使用变量吗?我试图避免必须进行手动查询,然后将其粘贴到XML中以执行存储过程。

例如,下面可以为其中一条XML记录传递NEWID()甚至SELECT语句 - 即ID?

exec spChangeRecordXML '<SP_ChangeRecordXML><Details><TableName>table1</TableName><ModificationType>Insert</ModificationType><Field><Name>ID</Name><Value>9b99e3ce-a675-44b9-9c6e-cedc1a1c2834</Value></Field><Field><Name>strtName</Name><Value>TEST2</Value></Field><Field><Name>strName</Name><Value>TEST2</Value></Field><Field><Name>DeptID</Name><Value>5894f6cc-7236-482a-af0f-08d0d15e6d5c</Value></Field></SP_ChangeRecordXML>'

2 个答案:

答案 0 :(得分:0)

SP的参数可以是您喜欢的任何数据类型,包括自定义数据类型(可以传递表参数的方式)。拥有带有xml参数的SP是完全可以接受的。

答案 1 :(得分:0)

看起来好像你想拥有一个通用SP用于任何类型的数据操作。您发送嘿,将以下字段插入我的表“table1”!,SP形成相应的语句并对数据库执行此操作。正确的吗?

关于您的问题:

拥有带XML参数的SP是完全可以的:

CREATE PROCEDURE dbo.TestWithXML(@SomeXML XML)
AS
BEGIN
    --Do something with the XML
    SELECT fld.value(N'(Name/text())[1]',N'nvarchar(max)')
          ,fld.value(N'(Value/text())[1]',N'nvarchar(max)')
    FROM @SomeXml.nodes(N'//Field') AS A(fld)
END
GO

- 现在我以各种方式称呼这个SP:

--fill a variable with a given XML
DECLARE @xml XML=
N'<SP_ChangeRecordXML>
  <Details>
    <TableName>table1</TableName>
    <ModificationType>Insert</ModificationType>
    <Field>
      <Name>ID</Name>
      <Value>9b99e3ce-a675-44b9-9c6e-cedc1a1c2834</Value>
    </Field>
    <Field>
      <Name>strtName</Name>
      <Value>TEST2</Value>
    </Field>
    <Field>
      <Name>strName</Name>
      <Value>TEST2</Value>
    </Field>
    <Field>
      <Name>DeptID</Name>
      <Value>5894f6cc-7236-482a-af0f-08d0d15e6d5c</Value>
    </Field>
  </Details>
</SP_ChangeRecordXML>'

--call the SP with an XML variable
EXEC dbo.TestWithXML @SomeXML=@xml;

--call the SP with an XML on string base
EXEC dbo.TestWithXML @SomeXML='<root><Field><Name>SomeName</Name><Value>SomeValue</Value></Field></root>';

--Set the variable from above to an XML "on the fly"
SET @xml=(SELECT 'testName' AS [Name], 'testValue' AS [Value] FOR XML PATH('Field'),ROOT('root'),TYPE);
--and call the SP with this
EXEC dbo.TestWithXML @SomeXML=@xml;

--Clean up
GO
DROP PROCEDURE dbo.TestWithXML;

对我来说更重要的是关于 此SP中的代码的问题。

通用方法很好,但在部署时往往变得丑陋......

XML作为参数非常棒,因为您可以传递任何类型和数量的数据。但如果你不知道里面是什么,SP就会丢失。这个XML的结构不能改变(否则你需要版本控制 - 更糟糕的是!)

从XML读取可能还需要一些元数据,尤其是数据类型。好吧,可以依赖隐式转换,将所有内容读作字符串并将其传递到引号内的INSERT。这在大多数情况下都有效(确保在ISO8601中使用日期时间,并且它不适用于base64编码的二进制文件......)。我可能会从DATA_TYPE阅读INFORMATION_SCHEMA.column

为所有表生成CRUD过程并使用XML的工作负载作为参数在内部调用它们可能是个好主意。这将允许您实现业务规则,而不会使您的通用SP膨胀。

更新修改XML

从你的评论中我得到了一个想法,你可能还需要别的东西:

DECLARE @xml XML=
N'<SP_ChangeRecordXML>
  <Details>
    <TableName>table1</TableName>
    <ModificationType>Insert</ModificationType>
    <Field>
      <Name>ID</Name>
      <Value>9b99e3ce-a675-44b9-9c6e-cedc1a1c2834</Value>
    </Field>
    <Field>
      <Name>strtName</Name>
      <Value>TEST2</Value>
    </Field>
    <Field>
      <Name>strName</Name>
      <Value>TEST2</Value>
    </Field>
    <Field>
      <Name>DeptID</Name>
      <Value>5894f6cc-7236-482a-af0f-08d0d15e6d5c</Value>
    </Field>
  </Details>
</SP_ChangeRecordXML>';

- 声明一个变量,然后保存新值

DECLARE @ReplaceID UNIQUEIDENTIFIER=NEWID();
SELECT @ReplaceID;

- 在XQuery/XPath sql:variable()

中使用此变量
SET @xml.modify(N'replace value of (//Field[Name="ID"]/Value/text())[1] with sql:variable("@ReplaceID")');
SELECT @xml;