Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在SQL Server中访问XML列中数据的首选方法 背景_Sql Server_Sql Execution Plan_Cross Apply_Xml Column - Fatal编程技术网

Sql server 在SQL Server中访问XML列中数据的首选方法 背景

Sql server 在SQL Server中访问XML列中数据的首选方法 背景,sql-server,sql-execution-plan,cross-apply,xml-column,Sql Server,Sql Execution Plan,Cross Apply,Xml Column,最近,我开始在SQLServer2005中更多地使用XML作为专栏。在昨天的一段停机时间里,我注意到我使用的两个链接表实际上只是一个临时链接,它让我感到厌烦,因为我不得不为几个连接编写更多的支持结构代码 为了实际生成这两个链接表的数据,我将两个XML字段传递给我的存储过程,存储过程写入主记录,将两个XML变量分解为@tables,并使用主记录中的新SCOPE\u IDENTITY()将它们插入到实际表中 经过一段时间之后,我决定完全取消这些表,只将XML存储在XML字段中。现在我知道这里有一些陷

最近,我开始在SQLServer2005中更多地使用XML作为专栏。在昨天的一段停机时间里,我注意到我使用的两个链接表实际上只是一个临时链接,它让我感到厌烦,因为我不得不为几个连接编写更多的支持结构代码

为了实际生成这两个链接表的数据,我将两个XML字段传递给我的存储过程,存储过程写入主记录,将两个XML变量分解为@tables,并使用主记录中的新
SCOPE\u IDENTITY()
将它们插入到实际表中

经过一段时间之后,我决定完全取消这些表,只将XML存储在XML字段中。现在我知道这里有一些陷阱,比如一般查询性能,
groupby
对XML数据不起作用。查询通常有点混乱,但总体上我喜欢这样,当我得到数据时,我现在可以使用
XElement

而且,这些东西不会被改变。这是一次性事件,所以我不必担心修改

我想知道获取这些数据的最佳方法。我的很多查询都涉及到根据子级记录甚至子级记录的条件获取主记录。数据库中的大多数存储过程都是这样做的,但规模要复杂得多,通常需要UDF和子查询才能有效地工作,但我编写了一个简单的示例来测试查询某些数据

INSERT INTO Customers VALUES ('Tom', '', '<PhoneNumbers><PhoneNumber Type="1" Value="01234 456789" /><PhoneNumber Type="2" Value="01746 482954" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Andy', '', '<PhoneNumbers><PhoneNumber Type="2" Value="07948 598348" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Mike', '', '<PhoneNumbers><PhoneNumber Type="3" Value="02875 482945" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Steve', '', '<PhoneNumbers></PhoneNumbers>')
真的吗?sql:变量感觉有点不健康。然而,它确实有效。然而,以一种更有意义的方式访问数据显然更加困难

方法2 更像是这样。我已经可以很容易地扩展它来做连接和所有其他的好东西。我以前在表值函数上使用过
交叉应用
,效果非常好。与上一个查询相比,此查询的执行计划更高级。诚然,我没有在这些表上做任何索引之类的工作,但这是整个批处理成本的97%

方法2(扩展) 这里的子句中的Nice
。我还可以做类似于
pt.PhoneType='Work'

最后 因此,我基本上获得了我想要的结果,但是当使用这种机制来查询少量XML数据时,有什么需要注意的吗?在精心设计的搜索过程中,性能会下降吗?这样的标记样式数据的存储是否开销过大

旁注
过去,我使用了
sp\u xml\u preparedocument
OPENXML
之类的东西,只是为了将列表传递到存储过程中,但相比之下,这就像呼吸了一口新鲜空气

对于存储在XML列中的一些关键信息项,我们采取的一种方法是在“父”表上“显示”它们作为计算的、持久化的属性。这是使用一个小的存储函数完成的

它工作得很好,因为每次XML更改时只计算一次值——只要不更改,就不需要重新计算,值会像其他任何列一样存储在表中

这也是伟大的,因为它可以索引!因此,如果你正在搜索和/或加入这样一个领域,这就像一个魅力

因此,您基本上需要一个存储函数,如下所示:

CREATE FUNCTION [dbo].[GetPhoneNo1](@DataXML XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
      DECLARE @result VARCHAR(20)

      SELECT 
        @result = @DataXML.value('(/PhoneNumbers/PhoneNumber[@Type="1"]/@Value)[1]', 'VARCHAR(50)')
      RETURN @result
END
如果你没有类型1的电话号码,你只会得到一个空的

然后,您需要使用计算的、持久化的列扩展父表:

ALTER TABLE dbo.Customers
   ADD PhoneNumberType1 AS dbo.GetPhoneNo1(PhoneNumbers)

正如您所看到的,它只适用于单个条目,但不幸的是,您无法显示整个属性列表。但是,如果您有一些关键项目,如ID或其他,您希望您的大多数行都有这些项目,那么这将是一种非常好的方法,可以更轻松、更高效地获取这些信息。

谢谢marc,这是一个非常好的技巧。我从没想过要这么做!正如您所说,我的大部分xml数据将以列表的形式(本质上链接到其他表)存在,这是我懒散地不放入正确的联接表的方式,但对于我得到的其他类型的表(针对某些记录存储可选参数),这是一件非常好的事情。再次感谢你,投了赞成票。
SELECT ct.ID, ct.CustomerName, ct.Notes, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') IN (SELECT ID FROM PhoneTypes)
CREATE FUNCTION [dbo].[GetPhoneNo1](@DataXML XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
      DECLARE @result VARCHAR(20)

      SELECT 
        @result = @DataXML.value('(/PhoneNumbers/PhoneNumber[@Type="1"]/@Value)[1]', 'VARCHAR(50)')
      RETURN @result
END
ALTER TABLE dbo.Customers
   ADD PhoneNumberType1 AS dbo.GetPhoneNo1(PhoneNumbers)