Return 来自 SQL 列的串联子字符串
Return Concatenated Substrings From Column In SQL
我正在尝试创建一个 SQL 视图,该视图将 return 来自 table.
列中子字符串的串联值
在我的示例中,在名为 'TrebuchetSettings' 的 table 中有一个标题为 'DefDetails' 的列,其中包含我需要连接在一起的 XML 值列表。
DefDetails 列将包含如下值,每条记录:
<Trebuchet>
<FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner>
<FolderList>
<FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" />
<FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>
使用 SQL 语句,我需要查询 TrebuchetSettings table 和 return 'FolderDef' 节点中 'Name' 字段的串联列表在上面的 XML 中,以 '/' 字符分隔,FolderDef 的 ID 与字符串开头列出的后续 FolderDef 的 ParentID 相匹配,因此串联结构表示文件夹结构。
由于此 table 中还有其他类型的记录,我的查询目前包含以下内容,以识别我需要从中提取这些子字符串的记录:
SELECT *
FROM TrebuchetSettings
WHERE DefType = 'FolderSetDef'
AND DefDetails LIKE '%(Folder ID)%'
在上面的示例 SQL 中,文件夹 ID 是一个 42 个字符的 ID,它将与另一个 table 中的值进行比较,以匹配 XML.
不幸的是,我没有这方面的起始代码集,因为我没有使用 SQL 中列的子字符串的经验,也不知道从哪里开始。
SQL 确实没有一种简单的方法可以在字符串中找到多个值...但是它确实具有将 xml 转换为 table 的功能,您可以正常查询。
如果有大量数据,您尝试做的事情可能非常慢...在这种情况下,管理一个(触发? ) 侧 table 将您的 ParentID 与包含行的 XML 的键一起保存在索引列中。这是 - 换句话说 - 有点像自己做的索引...
为了说明这一点:您有一个带有多个 ID(长字符串)的 table。然后,您必须在“/FolderDef”中找到所有包含此值为 "ParentID" 的 XML 条目。如果找到一个,您希望将特定 DefDetails 的所有名称连接起来。这意味着:对于第二个 table 中的任何 ID,您都必须一遍又一遍地扫描所有 DefDetails... LIKE
开头带有 %
的搜索将是 很慢。 XML-方法 .exist()
应该更快...
你可以试试这个:
我声明了一个 table 变量来模拟你的设置 table 有两个条目:
DECLARE @TrebuchetSettings TABLE(DefDetails XML);
INSERT INTO @TrebuchetSettings VALUES
(N'<Trebuchet>
<FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner>
<FolderList>
<FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" />
<FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>')
,(N'<Trebuchet>
<FolderSetDef ID="SomeOther" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>OtherOwner</Owner>
<FolderList>
<FolderDef ID="Other first ID" Name="Yearly Reports" ParentID="Other ParentID" Scope="Core" />
<FolderDef ID="Other second ID" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>');
用一个现有的 ParentID 和一个不存在的 ParentID 定义第二个 table
DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42));
INSERT INTO @YourOtherTable VALUES
('93af31a36cf8232f44265b40f9a1cd14d1e7000813')
,('Some not existing');
现在查找具有给定 FolderDef-ParentID 的所有记录,并将所有名称属性列为 /
分隔列表
SELECT ot.FolderID
,concatenated.Names
FROM @YourOtherTable AS ot
CROSS JOIN @TrebuchetSettings AS s
CROSS APPLY
(
SELECT STUFF(
(
SELECT '/' + A.NameAttr.value('@Name','varchar(max)')
FROM DefDetails.nodes('/Trebuchet/FolderSetDef/FolderList/FolderDef') AS A(NameAttr)
FOR XML PATH('')
),1,1,'')
) AS concatenated(Names)
WHERE s.DefDetails.exist('/Trebuchet/FolderSetDef/FolderList/FolderDef[@ParentID=sql:column("ot.FolderID")]')=1
结果为:
93af31a36cf8232f44265b40f9a1cd14d1e7000813 Yearly Reports/CSM Management Reports
我正在尝试创建一个 SQL 视图,该视图将 return 来自 table.
列中子字符串的串联值在我的示例中,在名为 'TrebuchetSettings' 的 table 中有一个标题为 'DefDetails' 的列,其中包含我需要连接在一起的 XML 值列表。
DefDetails 列将包含如下值,每条记录:
<Trebuchet>
<FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner>
<FolderList>
<FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" />
<FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>
使用 SQL 语句,我需要查询 TrebuchetSettings table 和 return 'FolderDef' 节点中 'Name' 字段的串联列表在上面的 XML 中,以 '/' 字符分隔,FolderDef 的 ID 与字符串开头列出的后续 FolderDef 的 ParentID 相匹配,因此串联结构表示文件夹结构。
由于此 table 中还有其他类型的记录,我的查询目前包含以下内容,以识别我需要从中提取这些子字符串的记录:
SELECT *
FROM TrebuchetSettings
WHERE DefType = 'FolderSetDef'
AND DefDetails LIKE '%(Folder ID)%'
在上面的示例 SQL 中,文件夹 ID 是一个 42 个字符的 ID,它将与另一个 table 中的值进行比较,以匹配 XML.
不幸的是,我没有这方面的起始代码集,因为我没有使用 SQL 中列的子字符串的经验,也不知道从哪里开始。
SQL 确实没有一种简单的方法可以在字符串中找到多个值...但是它确实具有将 xml 转换为 table 的功能,您可以正常查询。
如果有大量数据,您尝试做的事情可能非常慢...在这种情况下,管理一个(触发? ) 侧 table 将您的 ParentID 与包含行的 XML 的键一起保存在索引列中。这是 - 换句话说 - 有点像自己做的索引...
为了说明这一点:您有一个带有多个 ID(长字符串)的 table。然后,您必须在“/FolderDef”中找到所有包含此值为 "ParentID" 的 XML 条目。如果找到一个,您希望将特定 DefDetails 的所有名称连接起来。这意味着:对于第二个 table 中的任何 ID,您都必须一遍又一遍地扫描所有 DefDetails... LIKE
开头带有 %
的搜索将是 很慢。 XML-方法 .exist()
应该更快...
你可以试试这个:
我声明了一个 table 变量来模拟你的设置 table 有两个条目:
DECLARE @TrebuchetSettings TABLE(DefDetails XML);
INSERT INTO @TrebuchetSettings VALUES
(N'<Trebuchet>
<FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner>
<FolderList>
<FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" />
<FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>')
,(N'<Trebuchet>
<FolderSetDef ID="SomeOther" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)">
<Alias />
<Description />
<Owner>OtherOwner</Owner>
<FolderList>
<FolderDef ID="Other first ID" Name="Yearly Reports" ParentID="Other ParentID" Scope="Core" />
<FolderDef ID="Other second ID" Name="CSM Management Reports" ParentID="Root" Scope="Core" />
</FolderList>
</FolderSetDef>
</Trebuchet>');
用一个现有的 ParentID 和一个不存在的 ParentID 定义第二个 table
DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42));
INSERT INTO @YourOtherTable VALUES
('93af31a36cf8232f44265b40f9a1cd14d1e7000813')
,('Some not existing');
现在查找具有给定 FolderDef-ParentID 的所有记录,并将所有名称属性列为 /
分隔列表
SELECT ot.FolderID
,concatenated.Names
FROM @YourOtherTable AS ot
CROSS JOIN @TrebuchetSettings AS s
CROSS APPLY
(
SELECT STUFF(
(
SELECT '/' + A.NameAttr.value('@Name','varchar(max)')
FROM DefDetails.nodes('/Trebuchet/FolderSetDef/FolderList/FolderDef') AS A(NameAttr)
FOR XML PATH('')
),1,1,'')
) AS concatenated(Names)
WHERE s.DefDetails.exist('/Trebuchet/FolderSetDef/FolderList/FolderDef[@ParentID=sql:column("ot.FolderID")]')=1
结果为:
93af31a36cf8232f44265b40f9a1cd14d1e7000813 Yearly Reports/CSM Management Reports