sql >> データベース >  >> RDS >> PostgreSQL

XMLファイルをPostgreSQLにインポートする

    ネクロマンシング:実用的な例が必要な場合:

    DO $$
       DECLARE myxml xml;
    BEGIN
    
    myxml := XMLPARSE(DOCUMENT convert_from(pg_read_binary_file('MyData.xml'), 'UTF8'));
    
    DROP TABLE IF EXISTS mytable;
    CREATE TEMP TABLE mytable AS 
    
    SELECT 
         (xpath('//ID/text()', x))[1]::text AS id
        ,(xpath('//Name/text()', x))[1]::text AS Name 
        ,(xpath('//RFC/text()', x))[1]::text AS RFC
        ,(xpath('//Text/text()', x))[1]::text AS Text
        ,(xpath('//Desc/text()', x))[1]::text AS Desc
    FROM unnest(xpath('//record', myxml)) x
    ;
    
    END$$;
    
    
    SELECT * FROM mytable;
    

    またはノイズが少ない

    SELECT 
         (xpath('//ID/text()', myTempTable.myXmlColumn))[1]::text AS id
        ,(xpath('//Name/text()', myTempTable.myXmlColumn))[1]::text AS Name 
        ,(xpath('//RFC/text()', myTempTable.myXmlColumn))[1]::text AS RFC
        ,(xpath('//Text/text()', myTempTable.myXmlColumn))[1]::text AS Text
        ,(xpath('//Desc/text()', myTempTable.myXmlColumn))[1]::text AS Desc
        ,myTempTable.myXmlColumn as myXmlElement
    FROM unnest(
        xpath
        (    '//record'
            ,XMLPARSE(DOCUMENT convert_from(pg_read_binary_file('MyData.xml'), 'UTF8'))
        )
    ) AS myTempTable(myXmlColumn)
    ;
    

    この例のXMLファイル(MyData.xml)の場合:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <data-set>
        <record>
            <ID>1</ID>
            <Name>A</Name>
            <RFC>RFC 1035[1]</RFC>
            <Text>Address record</Text>
            <Desc>Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.</Desc>
        </record>
        <record>
            <ID>2</ID>
            <Name>NS</Name>
            <RFC>RFC 1035[1]</RFC>
            <Text>Name server record</Text>
            <Desc>Delegates a DNS zone to use the given authoritative name servers</Desc>
        </record>
    </data-set>
    

    注:
    MyData.xmlは、PG_Dataディレクトリ(pg_statディレクトリの親ディレクトリ)にある必要があります。
    例: /var/lib/postgresql/9.3/main/MyData.xml
    これにはPostGreSQL9.1以降が必要です

    全体として、次のようにファイルなしで実現できます。

    SELECT 
         (xpath('//ID/text()', myTempTable.myXmlColumn))[1]::text AS id
        ,(xpath('//Name/text()', myTempTable.myXmlColumn))[1]::text AS Name 
        ,(xpath('//RFC/text()', myTempTable.myXmlColumn))[1]::text AS RFC
        ,(xpath('//Text/text()', myTempTable.myXmlColumn))[1]::text AS Text
        ,(xpath('//Desc/text()', myTempTable.myXmlColumn))[1]::text AS Desc
        ,myTempTable.myXmlColumn as myXmlElement 
        -- Source: https://en.wikipedia.org/wiki/List_of_DNS_record_types
    FROM unnest(xpath('//record', 
     CAST('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <data-set>
        <record>
            <ID>1</ID>
            <Name>A</Name>
            <RFC>RFC 1035[1]</RFC>
            <Text>Address record</Text>
            <Desc>Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.</Desc>
        </record>
        <record>
            <ID>2</ID>
            <Name>NS</Name>
            <RFC>RFC 1035[1]</RFC>
            <Text>Name server record</Text>
            <Desc>Delegates a DNS zone to use the given authoritative name servers</Desc>
        </record>
    </data-set>
    ' AS xml)   
    )) AS myTempTable(myXmlColumn)
    ;
    

    MS-SQLとは異なり、xpath text()は空の文字列ではなくNULL値に対してNULLを返すことに注意してください。
    何らかの理由でNULLの存在を明示的に確認する必要がある場合は、[not(@xsi:nil="true")]を使用できます。 、名前の配列を渡す必要があります。そうしないと、エラーが発生します(ただし、xsi以外のすべての名前を省略できます)。

    SELECT 
         (xpath('//xmlEncodeTest[1]/text()', myTempTable.myXmlColumn))[1]::text AS c1
    
        ,(
        xpath('//xmlEncodeTest[1][not(@xsi:nil="true")]/text()', myTempTable.myXmlColumn
        ,
        ARRAY[
            -- ARRAY['xmlns','http://www.w3.org/1999/xhtml'], -- defaultns
            ARRAY['xsi','http://www.w3.org/2001/XMLSchema-instance'],
            ARRAY['xsd','http://www.w3.org/2001/XMLSchema'],        
            ARRAY['svg','http://www.w3.org/2000/svg'],
            ARRAY['xsl','http://www.w3.org/1999/XSL/Transform']
        ]
        )
        )[1]::text AS c22
    
    
        ,(xpath('//nixda[1]/text()', myTempTable.myXmlColumn))[1]::text AS c2 
        --,myTempTable.myXmlColumn as myXmlElement
        ,xmlexists('//xmlEncodeTest[1]' PASSING BY REF myTempTable.myXmlColumn) AS c1e
        ,xmlexists('//nixda[1]' PASSING BY REF myTempTable.myXmlColumn) AS c2e
        ,xmlexists('//xmlEncodeTestAbc[1]' PASSING BY REF myTempTable.myXmlColumn) AS c1ea
    FROM unnest(xpath('//row', 
         CAST('<?xml version="1.0" encoding="utf-8"?>
        <table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <row>
            <xmlEncodeTest xsi:nil="true" />
            <nixda>noob</nixda>
          </row>
        </table>
        ' AS xml)   
        )
    ) AS myTempTable(myXmlColumn)
    ;
    

    を実行して、フィールドがXMLテキストに含まれているかどうかを確認することもできます。
     ,xmlexists('//xmlEncodeTest[1]' PASSING BY REF myTempTable.myXmlColumn) AS c1e
    

    たとえば、XML値をCRUDのストアドプロシージャ/関数に渡す場合(上記を参照)

    また、XMLでnull値を渡す正しい方法は、<elementName xsi:nil="true" />であることに注意してください。 <elementName />ではありません または何もありません。属性にNULLを渡す正しい方法はありません(属性を省略することしかできませんが、大きなデータセットの列の数とその名前を推測するのは困難/遅くなります)。

    例えば

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <table>
        <row column1="a" column2="3" />
        <row column1="b" column2="4" column3="true" />
    </table>
    

    (よりコンパクトですが、インポートする必要がある場合、特に複数GBのデータを含むXMLファイルからの場合は非常に悪いです-stackoverflowデータダンプでその素晴らしい例を参照してください)

    SELECT 
         myTempTable.myXmlColumn
        ,(xpath('//@column1', myTempTable.myXmlColumn))[1]::text AS c1
        ,(xpath('//@column2', myTempTable.myXmlColumn))[1]::text AS c2
        ,(xpath('//@column3', myTempTable.myXmlColumn))[1]::text AS c3
        ,xmlexists('//@column3' PASSING BY REF myTempTable.myXmlColumn) AS c3e
        ,case when (xpath('//@column3', myTempTable.myXmlColumn))[1]::text is null then 1 else 0 end AS is_null 
    FROM unnest(xpath('//row', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <table>
        <row column1="a" column2="3" />
        <row column1="b" column2="4" column3="true" />
    </table>'
    ))  AS myTempTable(myXmlColumn) 
    


    1. SQLServerで文字列値とNULL値を連結する方法

    2. Dapper.NETおよび複数の結果セットを持つストアドプロシージャ

    3. JDBCとMySQLを使用した通信リンク障害の解決

    4. SQLServerテーブルのID列に手動で値を挿入する方法-SQLServer/T-SQLチュートリアルパート41