使用动态数量的元素或属性查询XML?

时间:2016-07-21 17:32:30

标签: xml sql-server-2008 stored-procedures

我在sql数据库中有employee表,它有一些固定的属性,比如employee_id,employee_name和employee_age,我允许用户在UI中添加他选择的n个属性。我想编写一个存储过程来存储用户为固定属性提供的数据以及他创建的属性。

我认为解决方案是将xml作为参数传递给存储过程,它将具有以下结构。如果未提供employee_age,则存储其默认值。

<employee>
  <employee_id>1<employee_id>
  <employee_name>XYZ<employee_name>
  <dynamic_attrib1>2.34</dynamic_attrib1>
  <dynamic_attrib2>abcd</dynamic_attrib2>
<employee>

我面临的问题是当我不知道用户提前设置的属性名称时如何解析这个xml?我可以这样做吗?还有其他方法可以做到吗?在此先感谢.. :))

1 个答案:

答案 0 :(得分:0)

首先:您给定的XML无效......

您要做的是一种名为键 - 值对(或属性 - 值 - 对实体 - 属性 - 值<的模式/ em>)并且总是非常麻烦...在数据库方面,我们更好地了解结果集的结构,否则你需要(丑陋)技巧。

您可以将您的给定XML转换为经典的键值对,如下所示:

DECLARE @xml XML=
'<employee>
  <employee_id>1</employee_id>
  <employee_name>XYZ</employee_name>
  <dynamic_attrib1>2.34</dynamic_attrib1>
  <dynamic_attrib2>abcd</dynamic_attrib2>
</employee>';

SELECT Nd.value('local-name(.)','varchar(max)') AS NodeName
      ,Nd.value('.','varchar(max)')
FROM @xml.nodes('employee/*') AS A(Nd);

如果有相应的条目,您可以使用帮助程序表更改NodeNames:

DECLARE @dynAttribs TABLE (AttribName VARCHAR(100),name VARCHAR(100));
INSERT INTO @dynAttribs VALUES
 ('dynamic_attrib1','Whatever can be 2.34')
,('dynamic_attrib2','Whatever can be "abcd"');

SELECT ISNULL(da.name, Nd.value('local-name(.)','varchar(max)')) AS NodeName
      ,Nd.value('.','varchar(max)')
FROM @xml.nodes('employee/*') AS A(Nd)
LEFT JOIN @dynAttribs AS da ON Nd.value('local-name(.)','varchar(max)')=da.AttribName;

您甚至可以在帮助程序表中包含数据类型,但这会强制您使用动态创建的语句和EXEC

比你的XML更好:

DECLARE @xml XML=
'<employee>
  <employee_id>1</employee_id>
  <employee_name>XYZ</employee_name>
  <DynamicAttributes>
      <attribute name="testname1">2.34</attribute>
      <attribute name="testname2">abcd</attribute>
  </DynamicAttributes>
</employee>';

SELECT e.value('employee_id[1]','int') AS Employee_Id
      ,e.value('employee_name[1]','varchar(max)') AS Employee_Name
      ,da.value('@name','varchar(max)') AS NodeName
      ,da.value('.','varchar(max)')
FROM @xml.nodes('employee') AS A(e)
OUTER APPLY e.nodes('DynamicAttributes/*') AS B(da);

但是你的问题没有提供足够的细节:你打算用这个做什么?结构(可能稍后!)更复杂(内部嵌套元素,如地址,电话号码)?最好定义一组确定的属性,并允许客户定义哪些属性未被使用。也许允许他们给出个人名字(别名)。但我不建议您提供一个完全开放的自己动手数据库。你会陷入深深的麻烦......