无法使用.nodes()将xml文档粉碎成表并交叉应用

时间:2016-09-12 15:07:41

标签: sql-server xml nodes cross-apply

我有一个xml文档,用于定义表的索引 这是一个例子:

<TargetDatabaseChanges>
     <Tables>
        <Table TName="Replacement" Schema="dbo" TextImageOnFileGroup="PRIMARY">
            <Indexes>
                <Index IndexName="IX_InventoryId" PrimaryKeyIndex="0" IndexDescription="NONCLUSTERED" PadIndex="0" Statistics_NoRecompute="0" IgnoreDupKey="0" AllowRowLocks="1" AllowPageLocks="1">
                  <IndexColumn ICName="ProductId" IsDescendingSort="0" OrdinalPosition="1" />
                </Index>
                <Index IndexName="IX_VendorId" PrimaryKeyIndex="0" IndexDescription="NONCLUSTERED" PadIndex="0" Statistics_NoRecompute="0" IgnoreDupKey="0" AllowRowLocks="1" AllowPageLocks="1">
                  <IndexColumn ICName="VendorId" IsDescendingSort="0" OrdinalPosition="1" />
                </Index>
            </Indexes>
        </Table>
        <Table TName="Activity" Schema="dbo" TextImageOnFileGroup="PRIMARY">
            <Indexes>
                 <Index IndexName="IX_ApplicationId" PrimaryKeyIndex="0" IsUnique="0" IndexDescription="NONCLUSTERED" PadIndex="0" Statistics_NoRecompute="0" IgnoreDupKey="0" AllowRowLocks="1" AllowPageLocks="1">
                    <IndexColumn ICName="ApplicationId" IsDescendingSort="0" OrdinalPosition="1" />
                </Index>
            </Indexes>
        </Table>
     </Tables>
</TargetDatabaseChanges>

当表有2个索引,每个索引与不同的列关联时,当我只能得到2行时,我得到4行数据。

这是我的选择陈述:

SELECT DBTables.Name.value('@TName', 'varchar(100)') AS TableName, DBTables.Name.value('@Schema', 'varchar(20)') AS SchemaName, 
        [Indexes].I.value('@IndexName', 'varchar(100)') AS IndexName,  [Indexes].I.value('@PrimaryKeyIndex', 'varchar(1)') AS PrimaryKeyIndex,  [Indexes].I.value('@IsUnique', 'varchar(1)') AS IsUnique, 
            [Indexes].I.value('@IndexDescription', 'varchar(120)') AS IndexDescription,
            [Indexes].I.value('@PadIndex', 'varchar(1)') AS PadIndex, [Indexes].I.value('@Statistics_NoRecompute', 'varchar(1)') AS StatisticsNoRecompute, [Indexes].I.value('@IgnoreDupKey', 'varchar(1)') AS IgnoreDupKey,
            [Indexes].I.value('@AllowRowLocks', 'varchar(1)') AS AllowRowLocks, [Indexes].I.value('@AllowPageLocks', 'varchar(1)') AS AllowPageLocks,
        [IndexColumn].IC.value('@ICName', 'varchar(100)') AS IndexColumnName, [IndexColumn].IC.value('@IsDescendingSort', 'varchar(1)') AS IsDescendingSort, 
        [IndexColumn].IC.value('@OrdinalPosition', 'varchar(2)') AS OrdinalPosition
FROM @XmlDBChanges.nodes('/TargetDatabaseChanges/Tables/Table') AS DBTables(Name)               
        CROSS APPLY DBTables.Name.nodes('Indexes/Index[@PrimaryKeyIndex=0]') AS [Indexes](I)
        CROSS APPLY DBTables.Name.nodes('Indexes/Index[@PrimaryKeyIndex=0]/IndexColumn') AS [IndexColumn](IC)

这是包含2个索引的表格表:

Replacement dbo IX_InventoryId  0   NULL    NONCLUSTERED    0   0   0   1   1   ProductId   0   1
Replacement dbo IX_InventoryId  0   NULL    NONCLUSTERED    0   0   0   1   1   VendorId    0   1
Replacement dbo IX_VendorId 0   NULL    NONCLUSTERED    0   0   0   1   1   ProductId   0   1
Replacement dbo IX_VendorId 0   NULL    NONCLUSTERED    0   0   0   1   1   VendorId    0   1

将索引IX_InventoryId与列VendorID相关联的行不应存在。与行IX_VendorId和ProductId列相同。

似乎CROSS APPLY DBTables.Name.nodes('Indexes/Index[@PrimaryKeyIndex=0]/IndexColumn') AS [IndexColumn](IC)正在执行此错误关联,但我不知道如何将其限制为只有IndexColumn的正确索引。

如何限制此关联?

2 个答案:

答案 0 :(得分:0)

想出来......万一其他人需要帮助...... 我更改了最后一个CROSS APPLY

CROSS APPLY DBTables.Name.nodes('Indexes/Index[@PrimaryKeyIndex=0]/IndexColumn') AS [IndexColumn](IC)

对此:

CROSS APPLY I.nodes('IndexColumn') AS [IndexColumn](IC)

I来自之前的CROSS APPLY' So the FROM`子句,如下所示:

`FROM @XmlDBChanges.nodes('/TargetDatabaseChanges/Tables/Table') AS DBTables(Name)              
        CROSS APPLY DBTables.Name.nodes('Indexes/Index[@PrimaryKeyIndex=0]') AS [Indexes](I)
        CROSS APPLY I.nodes('IndexColumn') AS [IndexColumn](IC)`

答案 1 :(得分:0)

cross apply没有必要。您可以像这样访问查询中的所有内容。

select t.v.value('../../../@TName','varchar(100)') TName,
t.v.value('../@IndexName','varchar(100)') IndexName,
t.v.value('@ICName','varchar(100)') ICName
from @x.nodes('TargetDatabaseChanges/Tables/Table/Indexes/Index/IndexColumn') t(v)
--if you want to filter
--from @x.nodes('TargetDatabaseChanges/Tables/Table/Indexes/Index[@PrimaryKeyIndex="0"]/IndexColumn') t(v)