我有一个名称表:
表A
John
Jim
Jason
Run Code Online (Sandbox Code Playgroud)
和一个 xml 字符串表:
表B
示例 1
<Show Title="" ShowTitle="=False" ShowLine="=False" ShowDescription="=False" ShowExpandCollapse="=False" IsVisible="=True" Description="" PageBreakAfter="=False" PageCaption="" AppLink="" InfoLink="" ImageLink="" Pause="=False" PauseMessage="" PauseMessageStyle="" PauseTitle="" ScreenStyle="">
<ShowOption Sequence="1" Name="Jim" Caption="Test" SelectOptionsImageLinkFieldExpression="ImageLink" />
</Show>
Run Code Online (Sandbox Code Playgroud)
示例 2
<vars>
<var name="MatrixName">
<value>="LockExitPairCompatability"</value>
</var>
<var name="Jason">
<value>=If(Exists(Minute.Value.Min), ToNumber(Minute.Value.Min), 0)</value>
</var>
<var name="MinNum">
<value>=If(Exists(Agency) AND Agency = "Cert", 0, MinNum)</value>
</var>
<var name="Where">
<value>="Site='" + Root.Site + "' AND HWType IN " + ToSQLArray(Root.Components[ActiveDoor].HardwareType)</value>
</var>
<var name="Where2">
<value>=" AND HWSubType IN " + ToSQLArray(Root.Components[ActiveDoor].LockSubType)</value>
</var>
<var name="CompatibleList">
<value>=usr.FetchMatrix</value>
</var>
</vars>
Run Code Online (Sandbox Code Playgroud)
示例 3
<rule>
<property name="CollectionVariable" DisplayName="Collection Variable" ValueType="RValueExpression">John</property>
<property name="KeyVariable" DisplayName="Key Variable" ValueType="LValueExpression">NextLock</property>
</rule>
Run Code Online (Sandbox Code Playgroud)
如何搜索以查找表 A 中的哪些名称不在任何 xml 字符串中?显示的数据只是示例。数据库中的 xml 具有各种不同的格式。
在 xml 数据中,它可能是“Root.Name”。即使使用“根”,我仍然希望它找到它。附在它上面。
我假设您想查看所有属性和所有元素。
对表 B 中的 XML 列使用函数exists和一个谓词来检查表A 中的值是否存在。函数sql:column用于将值从A 获取到XQuery 表达式中。
declare @A table(Name varchar(50));
insert into @A(Name) values('John'),('Jim'),('Jason'),('Mike');
declare @B table(XMLCol xml);
insert into @B(XMLCol) values
('<Show Title="" ShowTitle="=False" ShowLine="=False" ShowDescription="=False" ShowExpandCollapse="=False" IsVisible="=True" Description="" PageBreakAfter="=False" PageCaption="" AppLink="" InfoLink="" ImageLink="" Pause="=False" PauseMessage="" PauseMessageStyle="" PauseTitle="" ScreenStyle="">
<ShowOption Sequence="1" Name="Jim" Caption="Test" SelectOptionsImageLinkFieldExpression="ImageLink" />
</Show>'),
('<vars>
<var name="MatrixName"><value>="LockExitPairCompatability"</value></var>
<var name="Jason"><value>=If(Exists(Minute.Value.Min), ToNumber(Minute.Value.Min), 0)</value></var>
<var name="MinNum"><value>=If(Exists(Agency) AND Agency = "Cert", 0, MinNum)</value></var>
<var name="Where"><value>="Site=''" + Root.Site + "'' AND HWType IN " + ToSQLArray(Root.Components[ActiveDoor].HardwareType)</value></var>
<var name="Where2"><value>=" AND HWSubType IN " + ToSQLArray(Root.Components[ActiveDoor].LockSubType)</value></var>
<var name="CompatibleList"><value>=usr.FetchMatrix</value></var>
</vars>'),
('<rule>
<property name="CollectionVariable" DisplayName="Collection Variable" ValueType="RValueExpression">John</property>
<property name="KeyVariable" DisplayName="Key Variable" ValueType="LValueExpression">NextLock</property>
</rule>');
select A.Name
from @A as A
where not exists (
select *
from @B as B
where B.XMLCol.exist('(//@*, //text())[. = sql:column("A.Name")]') = 1
);
Run Code Online (Sandbox Code Playgroud)
//
搜索所有后代。
@
指定您正在查找属性。
*
是属性名称的通配符。
//text()
为您提供所有后代文本值(不是属性)。
(//@*, //text())
将属性与文本值结合起来
[. = sql:column("A.Name")]
检查当前值的谓词A.Name
。
如果你想检查一个值是否包含A.Name
你应该使用contains函数。
select A.Name
from @A as A
where not exists (
select *
from @B as B
where B.XMLCol.exist('(//@*, //text())[contains(., sql:column("A.Name"))]') = 1
);
Run Code Online (Sandbox Code Playgroud)
如果需要不区分大小写的比较,请将两个参数小写为contains
.
我喜欢找借口提起这个老栗子。它是一个基于 TSQL 的 XML 粉碎器,可将您的 XML 文档分解为一系列(某种)键值对。当你不知道你在寻找什么时,你必须寻找一切。
CREATE OR ALTER FUNCTION dbo.fnXmlNodeValue
(
@x xml
)
RETURNS TABLE
AS
RETURN
-- credit to https://stackoverflow.com/a/10885014/4709762
(
WITH cte AS
(
SELECT
lvl = 1,
Name = x.value('local-name(.)','NVARCHAR(MAX)'),
ParentName = CAST(NULL AS NVARCHAR(MAX)),
ParentPosition = CAST(1 AS INT),
NodeType = CAST(N'Element' AS NVARCHAR(20)),
FullPath = x.value('local-name(.)','NVARCHAR(MAX)'),
XPath = x.value('local-name(.)','NVARCHAR(MAX)')
+ N'[' + CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR) + N']',
Position = ROW_NUMBER() OVER(ORDER BY (SELECT 1)),
Tree = x.value('local-name(.)','NVARCHAR(MAX)'),
Value = x.value('text()[1]','NVARCHAR(MAX)'),
this = x.query('.'),
t = x.query('*'),
Sort = CAST(CAST(1 AS VARBINARY(4)) AS VARBINARY(MAX)),
ID = CAST(1 AS INT)
FROM @x.nodes('/*') a(x)
UNION ALL
SELECT
lvl = p.lvl + 1,
Name = c.value('local-name(.)','NVARCHAR(MAX)'),
ParentName = CAST(p.Name AS NVARCHAR(MAX)),
ParentPosition = CAST(p.Position AS INT),
NodeType = CAST(N'Element' AS NVARCHAR(20)),
FullPath = CAST(p.FullPath + N'/' + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)),
XPath = CAST(p.XPath + N'/'+ c.value('local-name(.)','NVARCHAR(MAX)')
+ N'['+ CAST(ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)') ORDER BY (SELECT 1)) AS NVARCHAR)+ N']' AS NVARCHAR(MAX)),
Position = ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)') ORDER BY (SELECT 1)),
Tree = CAST( SPACE(2 * p.lvl - 1) + N'|' + REPLICATE(N'-', 1) + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)),
Value = CAST( c.value('text()[1]','NVARCHAR(MAX)') AS NVARCHAR(MAX) ),
this = c.query('.'),
t = c.query('*'),
Sort = CAST(p.Sort + CAST( (lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS VARBINARY(4)) AS VARBINARY(MAX) ),
CAST((lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS INT)
FROM cte p
CROSS APPLY p.t.nodes('*') b(c)
)
,cte2 AS
(
SELECT
lvl AS Depth,
Name AS NodeName,
ParentName,
ParentPosition,
NodeType,
FullPath,
XPath,
Position,
Tree AS TreeView,
Value,
this AS XMLData,
Sort, ID
FROM cte
UNION ALL
SELECT
p.lvl,
x.value('local-name(.)','NVARCHAR(MAX)'),
p.Name,
p.Position,
CAST(N'Attribute' AS NVARCHAR(20)),
p.FullPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
p.XPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),
1,
SPACE(2 * p.lvl - 1) + N'|' + REPLICATE('-', 1)
+ N'@' + x.value('local-name(.)','NVARCHAR(MAX)'),
x.value('.','NVARCHAR(MAX)'),
NULL,
p.Sort,
p.ID + 1
FROM cte p
CROSS APPLY this.nodes('/*/@*') a(x)
)
SELECT
ID = ROW_NUMBER() OVER(ORDER BY Sort, ID),
ParentName,
ParentPosition,
Depth,
NodeName,
Position,
NodeType,
FullPath,
XPath,
TreeView,
Value,
XMLData
FROM cte2
);
Run Code Online (Sandbox Code Playgroud)
如何搜索以查找表 A 中的哪些名称不在任何 xml 字符串中?
在将您的 XML 文档分解为其键值对后,您执行反半连接以查找搜索目标中不存在的名称。
with shredder as (
select b.id,
x.NodeName,
x.NodeType,
x.FullPath,
x.Value
from TableB as b
cross apply dbo.fnXmlNodeValue(b.x) as x
)
select *
from TableA as a
where not exists (
select 1
from shredder as s
where s.Value = a.name
);
Run Code Online (Sandbox Code Playgroud)
...或者你总是crtl+f可以一堆¯\_(?)_/¯