【问题标题】:SQL 2008: getting rows with a join to an XML field?SQL 2008:获取与 XML 字段连接的行?
【发布时间】:2010-08-01 19:01:42
【问题描述】:

不确定这个问题是否会导致一些糟糕的表现,但现在似乎至少感觉“更好”..

我想要做的是:

我有一个名为 CONTACTS 的表,其中有一个名为 memberID 的主键字段

我还有一个 XML 字段,其中包含您朋友的 ID(例如).. 喜欢:

  <root><id>2</id><id>6</id><id>14</id></root>

所以我试图通过存储过程做的是传入你的会员 ID,并返回你所有的朋友信息,例如:

  select name, address, age, dob from contacts
  where id... xml join stuff...

我之前的工作方式(很好!)将所有 XML 节点 (/root/id) 选择到一个临时表中,然后从该临时表连接到联系人表以获取联系人字段...

非常感谢任何帮助.. .query .nodes 示例有点重载,当然这可能是更好的方法...

提前致谢!

我确实得到了一些工作,但看起来像一个 SQL frankenstein 语句! 基本上我需要从 XML 字段中获取朋友的联系 ID,然后像这样填充到临时表中:

Declare @contactIDtable TABLE (ID int)
INSERT INTO @contactIDtable (ID)
        SELECT CONVERT(INT,CAST(T2.memID.query('.') AS varchar(100))) AS friendsID
        FROM dbo.members
        CROSS APPLY memberContacts.nodes('/root/id/text()') AS T2(memID)

但是可恶!转换/转换的事情看起来很严重..因为我需要为下一位获取一个 INT,这是返回联系人数据的实际连接,如下所示:

SELECT memberID, memberName, memberAddress1
    FROM members
    INNER JOIN @contactIDtable cid
    ON members.memberID = cid.ID
    ORDER BY memberName

结果... 很好用.. 在我的例子中,我的 memberContacts XML 字段有 3 个节点(在这种情况下是 id),上面的查询返回了 3 行数据(memberID、memberName、memberAddress1)......

这当然是为了尝试保存创建一个多连接表,即我所有朋友 ID 的列表......只是不确定上面是否真的让这变得更快更容易......

有更多想法/尝试这样做的更有效方法???

【问题讨论】:

  • 能否介绍一个匹配联系人的表给好友,这样就不用每次查询都解析xml了?
  • 您可以轻松地将 SELECT CONVERT(INT,CAST(T2.memID.query('.') AS varchar(100))) 替换为 T2.memID.value('(.)[1]', 'INT') 并让 SQL Server 为您处理所有转换工作 - 一次且以高效的方式。
  • 感谢大家的回复.. 总是很有帮助。有一件事是肯定的,你不会对这些东西感到无聊!非常感谢

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


【解决方案1】:

SQL Server 用于读取 XML 的语法是最不直观的语法之一。理想情况下,您希望:

select   f.name
from     friends f
join     @xml x
on       x.id = f.id

相反,SQL Server 要求您拼写所有内容。要将 XML 变量或列转换为“行集”,您必须拼出确切的路径并想出两个别名:

@xml.nodes('/root/id') as table_alias(column_alias)

现在你必须向 SQL Server 解释如何将&lt;id&gt;1&lt;/id&gt; 转换为 int:

table_alias.column_alias.value('.', 'int')

所以你可以看到为什么大多数人更喜欢在客户端解码 XML :)

一个完整的例子:

declare @friends table (id int, name varchar(50))
insert @friends (id, name)
          select  2, 'Locke Lamorra'
union all select  6, 'Calo Sanzo'
union all select 10, 'Galdo Sanzo'
union all select 14, 'Jean Tannen'

declare @xml xml
set @xml = ' <root><id>2</id><id>6</id><id>14</id></root>'

select  f.name
from    @xml.nodes('/root/id') as table_alias(column_alias)
join    @friends f
on      table_alias.column_alias.value('.', 'int') = f.id

【讨论】:

  • 哇!多么好的例子!!!我永远不会知道如何做到这一点!你拿走了我的 x 行代码,并让基本上 4 行代码做同样的工作.. 而且不是 SQL 引擎专家,它看起来确实应该高效运行.. 再一次,整个想法是我需要一种方法保存有一个中间连接表(我可以很容易地管理 XML id 节点......即当然添加/删除一个节点)。我在这里所做的唯一更改当然是将@xml var 更改为: set @xml = (SELECT memberContacts FROM dbo.members WHERE memberID=@passedInMemberID) 非常感谢再次!!!!!!
【解决方案2】:

为了将您的 XML 内容作为“伪表”中的行获取,您需要在 XML 列上使用 .nodes() - 类似于:

DECLARE @xmlfield XML
SET @xmlfield = '<root><id>2</id><id>6</id><id>14</id></root>'

SELECT
   ROOT.ID.value('(.)[1]', 'int')
FROM
   @xmfield.nodes('/root/id') AS ROOT(ID)

SELECT
    (list of fields)
FROM
    dbo.Contacts c
INNER JOIN
    @xmlfield.nodes('/root/id') AS ROOT(ID) ON c.ID = Root.ID.value('(.)[1]', 'INT')  

基本上,.nodes() 定义了一个伪表 ROOT,其中包含一列 ID,它将为 XPath 表达式中的每个节点包含一行,.value() 从中选择一个特定值XML 片段。

【讨论】:

  • 不会cross apply 评估每一行的 XQuery 表达式吗?
  • @Andomar:是的,你是对的 - 在这个查询中真的没有必要 - 修正了我的答案
  • 谢谢你 marc_s !一些极好的见解.. 我显然有点停留在 SQL 编程的旧时代!
  • @David S:如果您对答案表示赞赏,请考虑为它投票!您可以使用答案旁边的向上和向下箭头进行投票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多