【问题标题】:Return Concatenated Substrings From Column In SQL从 SQL 中的列返回连接的子字符串
【发布时间】:2016-07-30 04:57:26
【问题描述】:

我正在尝试创建一个 SQL 视图,该视图将从表的列中返回子字符串的串联值。

在我的示例中,名为“TrebuchetSettings”的表中有一个标题为“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 表并返回上面 XML 中“FolderDef”节点内的“名称”字段的串联列表,用“/”字符分隔,FolderDef 的 ID 匹配字符串开头列出的后续FolderDef的ParentID,以便连接结构表示文件夹结构。

由于该表中还有其他类型的记录,我的查询当前包含以下内容,以确定我需要从中提取这些子字符串的记录:

SELECT *
FROM TrebuchetSettings
WHERE DefType = 'FolderSetDef'
AND DefDetails LIKE '%(Folder ID)%'

在上面的示例 SQL 中,文件夹 ID 是一个 42 个字符的 ID,它将与另一个表中的值进行比较,以匹配 XML 中的文件夹定义之一的 ID。

很遗憾,我没有这方面的起始代码集,因为我没有在 SQL 中处理列的子字符串的经验,也不知道从哪里开始。

【问题讨论】:

  • 我建议将Name 值移动/复制到单独的列中,并为DefDetails LIKE '%(Folder ID)%' 所在的行设置一个标志列。否则运行会很慢。 SQL 不是处理 XML 的最佳工具。

标签: sql sql-server xml substring string-concatenation


【解决方案1】:

如果有大量数据,您尝试执行的操作可能非常慢...在这种情况下,建议您管理一个(触发的?)边桌将您的 ParentID 与包含行的 XML 的键一起保存在索引列中。这 - 换句话说 - 类似于自我完成的索引......

只是为了说明这一点:您有一个包含多个 ID(长字符串)的表。然后,您必须在“/FolderDef”中找到包含此值作为“ParentID”的所有 XML 条目。如果您找到一个,您希望将特定 DefDetails 的所有名称连接起来。这意味着:对于第二个表中的任何 ID,您都必须一遍又一遍地扫描所有 DefDetails... 以 % 开头的 LIKE 搜索将非常慢。 XML 方法 .exist() 应该更快...

你可以试试这个:

我声明了一个表变量来模拟您的设置表,其中包含两个条目:

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 定义您的第二个表

DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42));
INSERT INTO @YourOtherTable VALUES
 ('93af31a36cf8232f44265b40f9a1cd14d1e7000813')
,('Some not existing');

现在查找具有给定 FolderDef-ParentID 的所有记录,并将所有名称属性列为 /-separated 列表

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

【讨论】:

    【解决方案2】:

    SQL 确实没有一种简单的方法来查找字符串中的多个值...但它确实具有将 xml 转换为可以正常查询的表的功能。

    试试这个:https://www.mssqltips.com/sqlservertip/2899/importing-and-processing-data-from-xml-files-into-sql-server-tables/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 2010-11-27
      相关资源
      最近更新 更多