如何确保 SQL 能够读取所有 XML 标记数据
Posted
技术标签:
【中文标题】如何确保 SQL 能够读取所有 XML 标记数据【英文标题】:How to ensure the SQL is able to read all XML tag data 【发布时间】:2014-12-13 02:51:49 【问题描述】:我在 SQL 表列中有以下 XML 数据:
<root>
<Physicians>
<name></name>
<picture></picture>
<gender></gender>
<langAccept>English</langAccept>
<langAccept>Spanish</langAccept> (can appear more times)
<insAccept>Aetna</insAccept>
<insAccept>BCBS</insAccept> (can appear more times)
<specialty></specialty>
<specialty2></specialty2>
<specialty3></specialty3>
</Physicians>
</root>
langAccept
和insAccept
可以出现多次,不知道出现了多少次。
我有以下 SQL 查询,目前没有考虑到“langAccept”和“insAccept”标签:
DECLARE @strProvider varchar(200)
SET @strProvider = '' --The Provider DropDownList
DECLARE @strSpecialty varchar(200)
SET @strSpecialty = '' --The Specialty DropDownList
DECLARE @strLocation varchar(200)
SET @strLocation = '' --The Location DropDownList
DECLARE @strGender varchar(200)
SET @strGender = '' --The Gender DropDownList
DECLARE @strInsurance varchar(200)
SET @strInsurance = '' --The Insurance DropDownList
DECLARE @strLanguage varchar(200)
SET @strLanguage = '' --The Language DropDownList
SELECT
[content_title] AS [Physician Name]
, [content_status] AS [Status]
, CAST([content_html] AS XML).value('(root/Physicians/picture/img/@src)[1]','varchar(255)') AS [Image]
, dbo.usp_ClearHTMLTags(CONVERT(nvarchar(600), CAST([content_html] AS XML).query('root/Physicians/gender'))) AS [Gender]
, CAST([content_html] AS XML).query('/root/Physicians/OfficeLocations/office1/a') AS [Office1]
, CAST([content_html] AS XML).query('/root/Physicians/OfficeLocations/office2/a') AS [Office2]
, CAST([content_html] AS XML).query('/root/Physicians/OfficeLocations/office3/a') AS [Office3]
, CAST([content_html] AS XML).query('/root/Physicians/OfficeLocations/office4/a') AS [Office4]
, CAST ([content_html] AS XML).query('/root/Physicians/specialty/a') AS [Specialty1]
, CAST ([content_html] AS XML).query('/root/Physicians/specialty2/a') AS [Specialty2]
FROM
[MYDB].[dbo].[content]
WHERE
[folder_id] = '188'
AND
(content_html LIKE '%<gender>%'+ @strGender+'%</gender>%')
AND
(content_html LIKE '%'+@strSpecialty+'%')
AND
(content_html LIKE '%'+@strLocation+'%')
AND
(content_status = 'A')
ORDER BY
[content_title]
我将使用 C# 作为代码隐藏获取该数据并写入我的 ASP.net 页面中的转发器。
如何修改我的 SQL 查询,以便它获取每个 langAccept
和 insAccept
标记的值(出现多次)。
【问题讨论】:
这应该复制行或放入一行(如English, Spanish
)?
如果我什至可以将它们放在 CSV 的列中,我可以在代码隐藏中操作它们。我认为添加一列并通过 CSV 插入每个事件对我来说是更好的途径。
使用逗号分隔符的列值不是一个好主意。这是一个糟糕的数据库设计的例子。相反,您应该寻求一个适当规范化的数据库,从中获取数据会容易得多。
因为这是我第一次使用它,我愿意提供建议和帮助:)。几乎这个查询将返回结果,我将在前端显示它作为结果。有时这些标签会出现 10+ 次,那么在一个表中创建 10+ 行有意义吗?
【参考方案1】:
您可以处理可能重复的任意数量的节点 - 但请注意,这总是会为单个条目 <Physician>
创建大量行。
试试这个:
DECLARE @Content TABLE (ID INT NOT NULL, XmlDAta XML)
INSERT INTO @content VALUES(1, '<root>
<Physicians>
<name>Dr. Excellent</name>
<picture></picture>
<gender>Male</gender>
<langAccept>English</langAccept>
<langAccept>Spanish</langAccept>
<insAccept>Aetna</insAccept>
<insAccept>BCBS</insAccept>
<specialty></specialty>
<specialty2></specialty2>
<specialty3></specialty3>
</Physicians>
</root>')
SELECT
ID,
PhysicianName = XC.value('(name)[1]', 'varchar(50)'),
Gender = XC.value('(gender)[1]', 'varchar(50)'),
LangSpoken = XLang.value('.', 'varchar(20)'),
InsAccepted = XIns.value('.', 'varchar(50)')
FROM
@Content
CROSS APPLY
XmlData.nodes('/root/Physicians') AS XT(XC)
CROSS APPLY
XC.nodes('langAccept') AS XT2(XLang)
CROSS APPLY
XC.nodes('insAccept') AS XT3(XIns)
通过在langAccept
和insAccept
节点内的insAccept
上使用.nodes()
,您可以获得所有定义的值 - 但您最终会得到单个<Physican>
节点的多个关系行:
更新:要从您自己的现有表中获取数据,请使用:
SELECT
ID,
PhysicianName = XC.value('(name)[1]', 'varchar(50)'),
Gender = XC.value('(gender)[1]', 'varchar(50)'),
LangSpoken = XLang.value('.', 'varchar(20)'),
InsAccepted = XIns.value('.', 'varchar(50)')
FROM
[MyDB].[dbo].Content
CROSS APPLY
CAST(content_html AS XML).nodes('/root/Physicians') AS XT(XC)
CROSS APPLY
XC.nodes('langAccept') AS XT2(XLang)
CROSS APPLY
XC.nodes('insAccept') AS XT3(XIns)
【讨论】:
不幸的是,XML 是从 SQL 表中读取的,我不确定 TAG 会出现多少次。我更新了我的问题,XML 已经在 SQL 表列中,而不是在文件中,抱歉。 @SearchForKnowledge:我的帖子在 SQL Server 表上工作......只需将我的@Content
替换为 [MYDB].[dbo].[content]
就可以了
DECLARE @Content [dbo].[content]
?
@SearchForKnowledge: 否 - 用您自己的数据库名称替换 SELECT
语句中的 @Content
.... 更新了我的回复
首先:您需要使用 your 列名(而不是 XmlData
)。其次:此列必须为 type XML
才能正常工作!【参考方案2】:
你可以这样试试。 这不是您问题的确切答案,但这可能会帮助您解决问题。
DECLARE @Data XMl = '<root><Physicians><name>sajsj</name><picture/><gender/><langAccept>English</langAccept><langAccept>Spanish</langAccept> (can appear more times)<insAccept>Aetna</insAccept><insAccept>BCBS</insAccept> (can appear more times)<specialty/><specialty2/><specialty3/></Physicians></root>';
;WITH CTE AS (
SELECT Dt.value('(name/text())[1]','VARCHAR(100)') AS Name,
Dt.query('(langAccept)') AS LangAccept,
Dt.query('(insAccept)') AS InsAccept
FROM
@Data.nodes('/root/Physicians') AS MyData(Dt)
),
CteGetAllLangAccept AS
(
SELECT
Ct.Name,
Data.Lang.value('(.)[1]', 'VARCHAR(50)') AS [LangAcceptValue],
NULL AS [InsAcceptDataValue]
FROM CTE Ct
CROSS APPLY Ct.LangAccept.nodes('/langAccept') AS Data(Lang)
),
CteGetInsAcceptData AS (
SELECT
Ct.Name,
NULL AS [LangAcceptValue],
InsAcceptData.Ins.value('(.)[1]', 'VARCHAR(50)') AS [InsAcceptDataValue]
FROM CTE Ct
CROSS APPLY Ct.InsAccept.nodes('/insAccept') AS InsAcceptData(Ins)
)
SELECT * FROM CteGetAllLangAccept![enter image description here][1]
UNION
SELECT * FROM CteGetInsAcceptData;
【讨论】:
感谢您的回复。 XML 数据已经在 SQL 表列中,我只是从列中读取数据并删除数据。我毫不怀疑它有效,但我的不是文件而是表格列。如何更改@Data
以指向表格列而不是硬编码字符串?我应该从列中获取值并将其存储在一个字符串中,然后将该字符串用于@Data
并使用上述查询吗?【参考方案3】:
我认为如果你想在客户端显示它,做几个查询会更容易,一个用于医生表,一个用于langAccept
,一个用于insAccept
:
declare @temp table (data xml)
insert into @temp (data)
select '<root>
<Physicians>
<name>House M.D.</name>
<picture></picture>
<gender>Male</gender>
<langAccept>English</langAccept>
<langAccept>Spanish</langAccept>
<insAccept>Aetna</insAccept>
<insAccept>BCBS</insAccept>
<specialty></specialty>
<specialty2></specialty2>
<specialty3></specialty3>
</Physicians>
<Physicians>
<name>Paracelsus</name>
<picture></picture>
<gender>Male</gender>
<langAccept>German</langAccept>
<langAccept>Latin</langAccept>
<specialty></specialty>
<specialty2></specialty2>
<specialty3></specialty3>
</Physicians>
</root>'
select
t.c.value('name[1]', 'nvarchar(max)') as name,
t.c.value('gender[1]', 'nvarchar(max)') as gender
from @temp as a
cross apply a.data.nodes('root/Physicians') as t(c)
select
t.c.value('name[1]', 'nvarchar(max)') as name,
l.c.value('.', 'nvarchar(max)') as langAccept
from @temp as a
cross apply a.data.nodes('root/Physicians') as t(c)
cross apply t.c.nodes('langAccept') as l(c)
select
t.c.value('name[1]', 'nvarchar(max)') as name,
l.c.value('.', 'nvarchar(max)') as insAccept
from @temp as a
cross apply a.data.nodes('root/Physicians') as t(c)
cross apply t.c.nodes('insAccept') as l(c)
【讨论】:
谢谢。 XML 数据是表中的一列,因此我必须从表中提取列然后提取以上是关于如何确保 SQL 能够读取所有 XML 标记数据的主要内容,如果未能解决你的问题,请参考以下文章
如何为 sklearn 的 CountVectorizer 编写自定义标记器以将所有 XML 标记以及打开和关闭标记之间的所有文本视为标记