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

3つのテーブルを持つPostgreSQLからXMLへ

    ネストされたテーブルには3つのレベルがあります。

    サンプルデータ:

    CREATE TABLE a(
      a_id integer primary key,
      name text
    );
    
    CREATE TABLE b(
      b_id integer primary key,
      a_id integer references a(a_id),
      val text
    );
    
    CREATE TABLE c(
      c_id serial primary key,
      b_id integer references b(b_id),
      blah text
    );
    
    INSERT INTO a(a_id, name) VALUES (1, 'fred'),(2, 'bert');
    
    INSERT INTO b(b_id, a_id, val) VALUES 
    (11, 1, 'x'), (12, 1, 'y'), (21, 2, 'a'), (22, 2, 'b');
    
    INSERT INTO c(b_id, blah) VALUES
    (11, 'whatever'), (11, 'gah'), (12, 'borkbork'), (22, 'fuzz');
    

    方法1:左結合を実行し、クライアントでXMLを処理します

    これを処理する最も簡単な方法は、3つのテーブルすべてに対して、最も外側から最も内側の順に左結合を実行することです。次に、結果セットを繰り返し処理し、そのレベルのサブジェクトが変更されるたびに1つの要素を閉じ、別の要素を開きます。

    select *
    from a left join b on (a.a_id = b.a_id)
           left join c on (b.b_id = c.b_id)
    order by a.a_id, b.b_id, c.c_id;
    

    次に、返された行をループし、各行について擬似コード

    cur_row = get_new_row()
    
    if (cur_row[b_id] != prev_row[b_id]) {
       emit_close_tableb();
    }
    if (cur_row[a_id] != prev_row[a_id]) {
       emit_close_tablea();
       emit_open_tablea(cur_row);
    }
    if (cur_row[b_id] != prev_row[b_id]) {
       emit_open_tableb(cur_row);
    }
    emit_tablec(cur_row);
    
    prev_row = cur_row;
    

    XMLを作成するには、 XMLWriterのようなものを使用します。 。クエリデータを読み取るには、PDOなどの任意のドライバーを使用できます。データセットが大きい場合は、カーソルを使用してデータを読み取ることを検討してください。

    これはうまく機能しますが、ロットを転送します nを転送するため、余分なデータの 各nの外部テーブルのデータのコピー それに関連付けられた内部テーブルの行。

    交換される余分なデータを減らすために、外部テーブルのIDのみを選択できます

    select a.a_id, b.b_id, c.*
    from a left join b on (a.a_id = b.a_id)
           left join c on (b.b_id = c.b_id)
    order by a.a_id, b.b_id, c.c_id;
    

    ...次に、新しいtablea / tablebに切り替えると、SELECT その後、残りの行。行を読み取っているメイン接続の結果セットとカーソルの状態を中断しないように、おそらく2番目の接続を使用してこれを行います。

    方法2:すべてをPostgreSQLで実行する

    小さいデータセットの場合、または大きいデータセットの内部レベルの場合は、PostgreSQLのXMLサポートを使用してXMLドキュメントを作成できます(例:

    )。
    WITH xmlinput AS (
      SELECT a, b, c
      FROM a
      LEFT JOIN b ON (a.a_id = b.a_id)
      LEFT JOIN c on (b.b_id = c.b_id)
      ORDER BY a.a_id, b.b_id, c.c_id
    )
    SELECT
      XMLELEMENT(name items,
        xmlagg(
          XMLELEMENT(name a,
            XMLFOREST((a).a_id AS a_id, (a)."name" AS name),
            b_xml
          )
        ORDER BY (a).a_id)
      ) AS output
    FROM
    (
      SELECT
        a,
        xmlagg(
          XMLELEMENT(name b,
            XMLFOREST((b).b_id AS b_id, (b).val AS val),
            c_xml
          )
        ORDER BY (b).b_id)
        AS b_xml
      FROM
      (
        SELECT
          a, b,
          xmlagg(
            XMLELEMENT(name c,
              XMLFOREST((c).c_id AS c_id, (c).blah AS blah)
            )
          ORDER BY (c).c_id)
          AS c_xml
        FROM xmlinput
        GROUP BY a, b
      ) c_as_xml
      GROUP BY a
    ) b_as_xml;
    

    ...しかし、実際には、そのようなコードを書くには、ある種のマゾヒストでなければなりません。かなり速いことがわかるかもしれませんが。

    クエリを理解するには、PostgreSQLXMLドキュメントを読む必要があります 。奇抜な構文はSQL/XML委員会によって考案されました。私たちを責めないでください。

    行変数にも注意してください 上記のコードでは、整理するために頻繁に使用されています。 ab およびc 行全体としてクエリの外側のレイヤーに渡されます。これにより、名前が衝突したときにエイリアスをいじる必要がなくなります。構文(a).a_id 、などは「a_id」を意味します 行変数aのフィールド "。詳細については、PostgreSQLのマニュアルを参照してください。

    上記はより良いXML構造を使用しています(以下のコメントを参照)。要素ではなく属性を出力する場合は、XMLFORESTを変更できます。 XMLATTRIBUTESの呼び出し 呼び出します。

    出力:

    <items><a><a_id>1</a_id><name>fred</name><b><b_id>11</b_id><val>x</val><c><c_id>1</c_id><blah>whatever</blah></c><c><c_id>2</c_id><blah>gah</blah></c></b><b><b_id>12</b_id><val>y</val><c><c_id>3</c_id><blah>borkbork</blah></c></b></a><a><a_id>2</a_id><name>bert</name><b><b_id>21</b_id><val>a</val><c/></b><b><b_id>22</b_id><val>b</val><c><c_id>4</c_id><blah>fuzz</blah></c></b></a></items>
    

    または、きれいに印刷されています:

    <?xml version="1.0" encoding="utf-16"?>
    <items>
        <a>
            <a_id>1</a_id>
            <name>fred</name>
            <b>
                <b_id>11</b_id>
                <val>x</val>
                <c>
                    <c_id>1</c_id>
                    <blah>whatever</blah>
                </c>
                <c>
                    <c_id>2</c_id>
                    <blah>gah</blah>
                </c>
            </b>
            <b>
                <b_id>12</b_id>
                <val>y</val>
                <c>
                    <c_id>3</c_id>
                    <blah>borkbork</blah>
                </c>
            </b>
        </a>
        <a>
            <a_id>2</a_id>
            <name>bert</name>
            <b>
                <b_id>21</b_id>
                <val>a</val>
                <c />
            </b>
            <b>
                <b_id>22</b_id>
                <val>b</val>
                <c>
                    <c_id>4</c_id>
                    <blah>fuzz</blah>
                </c>
            </b>
        </a>
    </items>
    

    より良いXMLを出力してください

    ちなみに、XMLでそのような属性を使用することは魅力的ですが、操作がすぐに難しく、醜くなります。通常のXML要素を使用してください:

      <Table 1>
        <Nr>1</Nr>
        <Name>blah</Name>
         <Table 2>
           <Nr>1</Nr>
           <Table 3>
              <Col1>42</Col1>
              <Col2>...</Col2>
              <Col3>...</Col3>
              <Col4>...</Col4>
              ...
           </Table 3>
         </Table 2>
       </Table 1>
    



    1. Entity Frameworkを介してOracleデータベースのIDを自動的に生成するにはどうすればよいですか?

    2. MySQL:CASTは括弧の前にスペースを必要としませんか?

    3. mysqlデータベースに接続できません[strato]

    4. Android-すでに閉じられているオブジェクトを再度開こうとします:loaderManagerを使用してSQLiteQuery