跨多行查询XML列

时间:2014-06-19 21:10:04

标签: sql sql-server xml tsql

在SQL Server中我试图查询具有XML列的表,该列中的XML类似于下面的

DECLARE @XML AS XML

SET @XML =
'<Root>
    <Stuff>
        <InsideStuff>1</InsideStuff>
        <InsideStuff>2</InsideStuff>
        <StuffIDontWant>9</StuffIDontWant>
    </Stuff>
    <Stuff>
        <InsideStuff>3</InsideStuff>
        <InsideStuff>4</InsideStuff>
        <StuffIDontWant>6</StuffIDontWant>
        <StuffIDontWant>7</StuffIDontWant>
    </Stuff>
</Root>'

SELECT TableAlias.ColumnAlias.value('(.)','nvarchar(max)') 
FROM @XML.nodes('/Root/Stuff/InsideStuff') AS TableAlias(ColumnAlias)

上面的代码会给我1,2,3,4这就是我想要的,但是我似乎无法弄清楚如何将其作为一种连接格式,我想做的事情就像

SELECT T1.Name 
FROM TableOne T1
INNER JOIN TableWithXml.ColumnWithXml.nodes('/Root/Stuff/InsideStuff') AS TableAlias(ColumnAlias) ON T1.ID = TableAlias(ColumnAlias)

在这种情况下如何格式化我的T-SQL?

1 个答案:

答案 0 :(得分:1)

主要目标是将XML展平到所需级别,并将其展平到可在查询中使用的表格中。

假设的表格结构:

DECLARE @TableWithXml TABLE (
    ID int IDENTITY(1,1),
    XmlCol XML
);

DECLARE @TableOne TABLE (
    ID int IDENTITY(1,1),
    StuffId int
);

解决方案1 ​​:如果您不关心除xml是否包含给定值之外的任何其他数据,只需将其展平一级并检查值:(sqlfiddle ):

SELECT t1.ID as T1ID, t2.ID as TXID, t2.XmlCol
FROM @TableOne t1
CROSS JOIN @TableWithXml t2
WHERE t1.StuffId IN (
    SELECT      XmlData.InsideStuff.value('(.)','int') as InsideStuff
    FROM        @TableWithXml tX
    CROSS APPLY tX.XmlCol.nodes('/Root/Stuff/InsideStuff') as XmlData(InsideStuff)
    WHERE       tX.ID = t2.ID
);

-- // Or alternatively...

SELECT      t1.ID as T1ID, FlattenedTable.TXID, FlattenedTable.InsideStuff, FlattenedTable.XmlCol
FROM        @TableOne t1
INNER JOIN  (
    SELECT      tx.ID as TXID, tx.XmlCol, XmlData.InsideStuff.value('(.)','int') as InsideStuff
    FROM        @TableWithXml tX
    CROSS APPLY tX.XmlCol.nodes('/Root/Stuff/InsideStuff') as XmlData(InsideStuff)
) as FlattenedTable ON t1.StuffId = FlattenedTable.InsideStuff

解决方案2 :如果您想使用XML数据,请将其展平(sqlfiddle):

SELECT      t1.ID as T1ID,
            tx.ID as TXID, 
            Stuffs_InsideStuff.val.value('(.)', 'int') as InsideStuffId, 
            Stuffs_StuffIDontWant.val.value('(.)', 'nvarchar(max)') as StuffIDontWant
FROM        @TableOne t1
INNER JOIN  (
    @TableWithXml tX
    CROSS APPLY tX.xmlCol.nodes('/Root/Stuff') as XmlData(Stuffs)
    CROSS APPLY XmlData.Stuffs.nodes('InsideStuff') as Stuffs_InsideStuff(val)
    CROSS APPLY XmlData.Stuffs.nodes('StuffIDontWant') as Stuffs_StuffIDontWant(val)
) on t1.stuffId = Stuffs_InsideStuff.val.value('(.)', 'int');