如何粉碎一般定义的关联XML(没有不同的元素名称)

时间:2016-07-14 22:16:11

标签: sql-server xml

第三方将提供我需要粉碎成SQL Server关系格式的XML。 XML在某些方面很不寻常

  1. 显然,为了更灵活,XML提供了一个带有“columnNames”的部分。之后提供的实际数据没有不同的元素名称,我想我需要根据顺序映射列名。

  2. 提供实际数据的“行”部分没有标题属性或其他方式关联行中的一组字段。

  3. 以下是数据的简化版本:

    <ReportData>
        <ColumnName>SOLD_DATE</ColumnName>
        <ColumnName>STORE_NUMBER</ColumnName>
        <ColumnName>PHONE_NUMBER</ColumnName>
        <ColumnName>FAX_NUMBER</ColumnName>
        <Row>
            <Col>03/31/2016</Col>
            <Col>1234</Col>
            <Col>(425) 673-7065</Col>
            <Col>(425) 278-4974</Col>
        </Row>
        <Row>
            <Col>05/05/2016</Col>
            <Col>3456</Col>
            <Col>(425) 555-7065</Col>
            <Col>(425) 444-4974</Col>
        </Row>
    </ReportData>
    

    如何将其转换为表格:

    Sold_Date   Store_Number    Phone_Number    Fax_Number
    3/31/2016   1234            (425) 673-7065  (425) 278-4974
    5/5/2016    3456            (425) 555-7065  (425) 444-4974
    

    感谢您的任何想法。我最初考虑使用带有边缘表的OpenXML来利用父/兄弟节点值,但似乎应该有更好的方法。

3 个答案:

答案 0 :(得分:2)

如果您需要这样的输出,需要动态命名列。这是不可能的 - 除非您使用动态SQL 。试试这个:

07-15 03:53:11.298 30926-30956/com.test.skintest E/AndroidRuntime: FATAL EXCEPTION: GLThread 14997
                                                               Process: com.test.skintest, PID: 30926
                                                               com.badlogic.gdx.utils.SerializationException: Error reading file: uiskin.json
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:97)
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:74)
                                                                   at com.test.skintest.MainClass.create(MainClass.java:22)
                                                                   at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:290)
                                                                   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511)
                                                                   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)
                                                                Caused by: com.badlogic.gdx.utils.SerializationException: Error reading file: uiskin.json
                                                                   at com.badlogic.gdx.utils.Json.fromJson(Json.java:694)
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:95)
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:74) 
                                                                   at com.test.skintest.MainClass.create(MainClass.java:22) 
                                                                   at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:290) 
                                                                   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511) 
                                                                   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239) 
                                                                Caused by: com.badlogic.gdx.utils.SerializationException: Error parsing file: uiskin.json
                                                                   at com.badlogic.gdx.utils.JsonReader.parse(JsonReader.java:77)
                                                                   at com.badlogic.gdx.utils.Json.fromJson(Json.java:692)
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:95) 
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:74) 
                                                                   at com.test.skintest.MainClass.create(MainClass.java:22) 
                                                                   at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:290) 
                                                                   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511) 
                                                                   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239) 
                                                                Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Error reading file: uiskin.json (Internal)
                                                                   at com.badlogic.gdx.backends.android.AndroidFileHandle.read(AndroidFileHandle.java:77)
                                                                   at com.badlogic.gdx.files.FileHandle.reader(FileHandle.java:163)
                                                                   at com.badlogic.gdx.utils.JsonReader.parse(JsonReader.java:75)
                                                                   at com.badlogic.gdx.utils.Json.fromJson(Json.java:692) 
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:95) 
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:74) 
                                                                   at com.test.skintest.MainClass.create(MainClass.java:22) 
                                                                   at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:290) 
                                                                   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511) 
                                                                   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239) 
                                                                Caused by: java.io.FileNotFoundException: uiskin.json
                                                                   at android.content.res.AssetManager.openAsset(Native Method)
                                                                   at android.content.res.AssetManager.open(AssetManager.java:334)
                                                                   at android.content.res.AssetManager.open(AssetManager.java:308)
                                                                   at com.badlogic.gdx.backends.android.AndroidFileHandle.read(AndroidFileHandle.java:75)
                                                                   at com.badlogic.gdx.files.FileHandle.reader(FileHandle.java:163) 
                                                                   at com.badlogic.gdx.utils.JsonReader.parse(JsonReader.java:75) 
                                                                   at com.badlogic.gdx.utils.Json.fromJson(Json.java:692) 
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:95) 
                                                                   at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:74) 
                                                                   at com.test.skintest.MainClass.create(MainClass.java:22) 
                                                                   at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:290) 
                                                                   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511) 
                                                                   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239) 

唯一可以依赖,是XML中的排序

DECLARE @xml XML=
'<ReportData>
    <ColumnName>SOLD_DATE</ColumnName>
    <ColumnName>STORE_NUMBER</ColumnName>
    <ColumnName>PHONE_NUMBER</ColumnName>
    <ColumnName>FAX_NUMBER</ColumnName>
    <Row>
        <Col>03/31/2016</Col>
        <Col>1234</Col>
        <Col>(425) 673-7065</Col>
        <Col>(425) 278-4974</Col>
    </Row>
    <Row>
        <Col>05/05/2016</Col>
        <Col>3456</Col>
        <Col>(425) 555-7065</Col>
        <Col>(425) 444-4974</Col>
    </Row>
</ReportData>';

WITH ColumnNames AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ColNr ,C.value('.','nvarchar(max)') AS Caption FROM @xml.nodes('/ReportData/ColumnName') AS A(C) ) ,RowLines AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNr ,R.query('.') AS RowXML FROM @xml.nodes('/ReportData/Row') AS A(R) ) ,RowValues AS ( SELECT RowNr ,ROW_NUMBER() OVER(PARTITION BY RowNr ORDER BY (SELECT NULL)) AS ValNr ,C.value('.','nvarchar(max)') AS ColVal FROM RowLines CROSS APPLY RowXML.nodes('Row/Col') AS A(C) ) SELECT * INTO #tmpResult FROM RowValues INNER JOIN ColumnNames ON ColNr=ValNr ORDER BY RowNr,ValNr; 现在有这样的内容:

#tmpResult

现在我们需要一个动态创建的+-------+-------+----------------+-------+--------------+ | RowNr | ValNr | ColVal | ColNr | Caption | +-------+-------+----------------+-------+--------------+ | 1 | 1 | 03/31/2016 | 1 | SOLD_DATE | +-------+-------+----------------+-------+--------------+ | 1 | 2 | 1234 | 2 | STORE_NUMBER | +-------+-------+----------------+-------+--------------+ | 1 | 3 | (425) 673-7065 | 3 | PHONE_NUMBER | +-------+-------+----------------+-------+--------------+ | 1 | 4 | (425) 278-4974 | 4 | FAX_NUMBER | +-------+-------+----------------+-------+--------------+ | 2 | 1 | 05/05/2016 | 1 | SOLD_DATE | +-------+-------+----------------+-------+--------------+ | 2 | 2 | 3456 | 2 | STORE_NUMBER | +-------+-------+----------------+-------+--------------+ | 2 | 3 | (425) 555-7065 | 3 | PHONE_NUMBER | +-------+-------+----------------+-------+--------------+ | 2 | 4 | (425) 444-4974 | 4 | FAX_NUMBER | +-------+-------+----------------+-------+--------------+ 语句:

PIVOT

这就是结果:

DECLARE @colNames NVARCHAR(MAX)=
(
    STUFF(
    (
        SELECT DISTINCT ',' + Caption + ''
        FROM #tmpResult
        FOR XML PATH('')
    ),1,1,''
    )
);

DECLARE @cmd NVARCHAR(MAX)=
    'SELECT p.*
    FROM
    (
        SELECT RowNr,ColVal,Caption FROM #tmpResult
    ) AS tbl
    PIVOT
    (
        MAX(ColVal) FOR Caption IN(' + @colNames + ')
    ) AS p;';

EXEC(@cmd);

清理

+-------+----------------+----------------+------------+--------------+
| RowNr | FAX_NUMBER     | PHONE_NUMBER   | SOLD_DATE  | STORE_NUMBER |
+-------+----------------+----------------+------------+--------------+
| 1     | (425) 278-4974 | (425) 673-7065 | 03/31/2016 | 1234         |
+-------+----------------+----------------+------------+--------------+
| 2     | (425) 444-4974 | (425) 555-7065 | 05/05/2016 | 3456         |
+-------+----------------+----------------+------------+--------------+

答案 1 :(得分:1)

考虑查询<Row>个节点,然后按节点索引选择<Col>

IF OBJECT_ID('tempdb..#demo', 'U') IS NOT NULL drop table #demo;
CREATE TABLE #demo (data xml)
INSERT INTO #demo (data) 
VALUES('<ReportData>
            <ColumnName>SOLD_DATE</ColumnName>
            <ColumnName>STORE_NUMBER</ColumnName>
            <ColumnName>PHONE_NUMBER</ColumnName>
            <ColumnName>FAX_NUMBER</ColumnName>
            <Row>
                <Col>03/31/2016</Col>
                <Col>1234</Col>
                <Col>(425) 673-7065</Col>
                <Col>(425) 278-4974</Col>
            </Row>
            <Row>
                <Col>05/05/2016</Col>
                <Col>3456</Col>
                <Col>(425) 555-7065</Col>
                <Col>(425) 444-4974</Col>
            </Row>
       </ReportData>');

SELECT
    Sold_Date = item.value('(Col)[1]', 'varchar(50)'), 
    Store_Number = item.value('(Col)[2]', 'varchar(50)'), 
    Phone_Number = item.value('(Col)[3]', 'varchar(50)'),
    Fax_Number = item.value('(Col)[4]', 'varchar(50)') 
FROM #demo
CROSS APPLY
  data.nodes('/ReportData/Row') AS dt(item);

-- Sold_Date    Store_Number   Phone_Number     Fax_Number
-- 03/31/2016   1234           (425) 673-7065   (425) 278-4974
-- 05/05/2016   3456           (425) 555-7065   (425) 444-4974

答案 2 :(得分:0)

可能没有优雅的解决方案。至少可以将原始数据转换为更好的可读性。这是一个例子。

declare @x xml=
'<ReportData>
    <ColumnName>SOLD_DATE</ColumnName>
    <ColumnName>STORE_NUMBER</ColumnName>
    <ColumnName>PHONE_NUMBER</ColumnName>
    <ColumnName>FAX_NUMBER</ColumnName>
    <Row>
        <Col>03/31/2016</Col>
        <Col>1234</Col>
        <Col>(425) 673-7065</Col>
        <Col>(425) 278-4974</Col>
    </Row>
    <Row>
        <Col>05/05/2016</Col>
        <Col>3456</Col>
        <Col>(425) 555-7065</Col>
        <Col>(425) 444-4974</Col>
    </Row>
</ReportData>'
declare @data xml

;with nm as (--ColumnNames
select  t.v.value('ColumnName[1]','varchar(20)') c1,
        t.v.value('ColumnName[2]','varchar(20)') c2,
        t.v.value('ColumnName[3]','varchar(20)') c3,
        t.v.value('ColumnName[4]','varchar(20)') c4
from @x.nodes('ReportData') t(v)
)
,ro as (--rows
select t.v.value('Col[1]','varchar(20)') r1, 
       t.v.value('Col[2]','varchar(20)') r2,
       t.v.value('Col[3]','varchar(20)') r3,
       t.v.value('Col[4]','varchar(20)') r4
from @x.nodes('ReportData/Row') t(v)
)
select @data= (select cast('<row '+nm.c1+'="'+ro.r1+'" '
         +nm.c2+'="'+ro.r2+'" '
         +nm.c3+'="'+ro.r3+'" '
         +nm.c4+'="'+ro.r4+'" />' as xml) 
from ro
cross apply nm
for xml  path(''),root)

select @data d

生成的XML看起来像这样。

<root>
  <row SOLD_DATE="03/31/2016" STORE_NUMBER="1234" PHONE_NUMBER="(425) 673-7065" FAX_NUMBER="(425) 278-4974" />
  <row SOLD_DATE="05/05/2016" STORE_NUMBER="3456" PHONE_NUMBER="(425) 555-7065" FAX_NUMBER="(425) 444-4974" />
</root>