从SQL

时间:2016-07-30 04:57:26

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

我试图创建一个SQL视图,该视图将从表中的列中返回子串的连接值。

在我的示例中,有一个标题为“DefDetails'在名为' TrebuchetSettings'的表中,它包含我需要连接在一起的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表并返回&#39; Name&#39;的串联列表。 “FolderDef”中的字段&#39;上面的XML中的节点,由&#39; /&#39;分隔开使用FolderDef的字符,其ID与字符串开头列出的后续FolderDef的ParentID匹配,以便连接结构表示文件夹结构。

由于此表中还有其他类型的记录,因此我的查询当前包含以下内容,以识别从以下位置提取这些子字符串所需的记录:

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

在上面的示例SQL中,Folder ID是一个42个字符的ID,将与另一个表中的值进行比较,以匹配XML中某个Folder Defs的ID。

不幸的是,我没有一套启动代码,因为我没有使用SQL中的列子串的经验,也不知道从哪里开始。

2 个答案:

答案 0 :(得分:1)

如果有大量数据,您尝试做的事情可能非常慢 ...在这种情况下,管理一个(触发?)边桌是一个很好的建议将您的ParentID保存在索引列中,同时保存包含XML行的键。换句话说,就像自我完成的索引......

只是为了清楚说明:你有一个包含多个ID(长字符串)的表。然后,您必须找到包含此值的所有XML条目为&#34; ParentID&#34;在&#34; / FolderDef&#34;。如果找到一个,则需要连接特定DefDetails的所有名称。这意味着:对于第二个表格中的任何ID,您必须一遍又一遍地扫描所有DefDetail ...一开始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和一个不存在的

定义您的第二个表
DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42));
INSERT INTO @YourOtherTable VALUES
 ('93af31a36cf8232f44265b40f9a1cd14d1e7000813')
,('Some not existing');

现在找到具有给定FolderDef-ParentID的所有记录,并将所有Name属性列为/ - 分隔列表

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

答案 1 :(得分:0)

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

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