SQL 交叉应用没有结果

Posted

技术标签:

【中文标题】SQL 交叉应用没有结果【英文标题】:SQL Cross Apply no results 【发布时间】:2018-03-20 15:53:43 【问题描述】:

我有 丑陋的 XML,看起来像这样:

<?xml version="1.0"?>
<MainTag xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" RecordID="201801026543210">
    <Field Name="TheFieldName">
        <FieldValue>Field Contents</FieldValue>
        <ListTag>
            <ListItem>
                <Value>This List Value</Value>
                <Source>source.txt</Source>
                <ListType>text</ListType>
                <ItemNumber>6912</ItemNumber>
                <MoreData>some text here</MoreData>
                <Address>address data</Address>
                <Ranking>102</Ranking>
            </ListItem>
            <ListItem>
                <Value>Another List Value</Value>
                <Source>other.txt</Source>
                <ListType>text</ListType>
                <ItemNumber>7919</ItemNumber>
                <MoreData>more text here</MoreData>
                <Address>address data</Address>
                <Ranking>41</Ranking>
            </ListItem>
        </ListTag>
    </Field>
</MainTag>

我想要的是给我一个电子表格的查询结果,本质上是:

RecordID        FieldName       FieldValue      ListValue           ListSource  ListType    ListItemNumber  …
201801026543210 TheFieldName    Field Contents  This List Value     source.txt  text        6912    
201801026543210 TheFieldName    Field Contents  Another List Value  other.txt   text        7919    

为了增加乐趣,XML 存储在 varchar 字段中,而不是 XML 字段中。

作为我尝试过的示例数据和查询:

DECLARE @Tbl TABLE ( 
    TblID varchar(15)
    , Fld varchar(max) 
)
INSERT INTO @Tbl SELECT '201801026543210', '<?xml version="1.0"?><MainTag xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" RecordID="201801026543210"><Field Name="TheFieldName"><FieldValue>Field Contents</FieldValue><ListTag><ListItem><Value>This List Value</Value><Source>source.txt</Source><ListType>text</ListType><ItemNumber>6912</ItemNumber><MoreData>some text here</MoreData><Address>address data</Address><Ranking>102</Ranking></ListItem><ListItem><Value>Another List Value</Value><Source>other.txt</Source><ListType>text</ListType><ItemNumber>7919</ItemNumber><MoreData>more text here</MoreData><Address>address data</Address><Ranking>41</Ranking></ListItem></ListTag></Field></MainTag>'


-- this shows that i am reading the main tag
SELECT t.r.value('@RecordID','varchar(15)') AS RecordID
    , t.r.query('.') as fullvalue
FROM (
    SELECT top 10 CONVERT(xml, Fld) AS Fld, TblID
    FROM @Tbl 
) AS s
CROSS APPLY Fld.nodes('/MainTag') AS t(r)


-- and this works to read the attribute from the first field
SELECT t.r.value('@RecordID', 'varchar(18)') AS RecordID
    , f.r.value('@Name', 'varchar(100)') AS Field
FROM (
    SELECT top 10 CONVERT(xml, Fld) AS Fld, TblID
    FROM @Tbl 
) AS s
CROSS APPLY Fld.nodes('/MainTag') AS t(r)
CROSS APPLY Fld.nodes('/MainTag/Field') AS f(r)


-- this does NOT work to read the second field
SELECT t.r.value('@RecordID','varchar(18)') AS RecordID
    , f.r.value('.', 'varchar(100)') AS ValueF
    , p.r.query('.') AS QueryP
    , p.r.value('.', 'varchar(100)') AS ValueP
FROM (
    SELECT top 10 CONVERT(xml, Fld) AS Fld, TblID
    FROM @Tbl 
) AS s
CROSS APPLY Fld.nodes('/MainTag') AS t(r)
CROSS APPLY Fld.nodes('/MainTag/Field') AS f(r)
CROSS APPLY Fld.nodes('/MainTag/FieldValue') AS p(r)


-- i honestly feel like this should be using nodes off of the parent nodes method
-- , but this is NOT working either
SELECT t.r.value('@RecordID','varchar(18)') AS RecordID
    , p.r.query('.') AS FieldValue
FROM (
    SELECT top 10 CONVERT(xml, Fld) AS Fld, TblID
    FROM @Tbl 
) AS s
CROSS APPLY s.Fld.nodes('/MainTag') AS t(r)
CROSS APPLY t.r.nodes('/MainTag/FieldValue') AS p(r)

我看到了一些其他问题/示例,这些问题/示例仅包含第一个条目。我不要那个。我想要一大堆数据。我希望为每个“ListItem”重复唯一字段。换一种说法:我知道这类似于一对多连接,其中“one”表中的字段将针对“many”表中的每一行重复。

从技术上讲,在我的数据中也可能有多个“字段”。 该字段只有一个 FieldValue。 有一个或多个 ListItem。

【问题讨论】:

顺便说一句:这不是一个 XML...这是一个相当漂亮的XML :-) btw2:这是一个很好的问题:样本、MCVE、自己的尝试……我这边+1 我被卡住的部分是 FieldValue。在对这个问题进行缩进后,我意识到我试图在 /MainTag/FieldValue 中访问它,但它位于 /MainTag/Field/FieldValue。 【参考方案1】:

用这个查询试试:

SELECT s.Fld.value('(/MainTag/@RecordID)[1]','bigint') AS RecordID
      ,A.f.value('@Name','nvarchar(max)') as FieldName
      ,A.f.value('(FieldValue/text())[1]','nvarchar(max)') as FieldValue
      ,B.li.value('(Value/text())[1]','nvarchar(max)') as ListValue
      ,B.li.value('(Source/text())[1]','nvarchar(max)') as ListSource
      --and so on
FROM (
    SELECT top 10 CONVERT(xml, Fld) AS Fld, TblID
    FROM @Tbl 
) AS s
CROSS APPLY Fld.nodes('/MainTag/Field') AS A(f)
CROSS APPLY A.f.nodes('ListTag/ListItem') AS B(li)

提示

如果有机会将存储空间从 VARCHAR 更改为 XML,那是值得的......

【讨论】:

等待您的答复

以上是关于SQL 交叉应用没有结果的主要内容,如果未能解决你的问题,请参考以下文章

如何使用交叉应用字符串拆分结果更新sql中的表?

SQL 在视图中使用交叉引用两个表的结果创建列

交叉应用使用的子查询不返回结果

sql总结---比较全

交叉熵

从 MS Access 中将交叉表查询结果导出到 Excel