PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

PostgreSQL ke XML dengan 3 Tabel

Anda memiliki tiga tingkat tabel bersarang.

Contoh data:

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');

Metode 1:Lakukan join kiri, tangani XML di klien

Cara paling sederhana untuk menangani ini adalah dengan melakukan join kiri pada ketiga tabel, diurutkan dari terluar ke terdalam. Kemudian Anda mengulangi set hasil, menutup satu elemen dan membuka yang lain setiap kali subjek pada tingkat itu berubah.

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;

lalu ulangi baris yang dikembalikan, dan untuk setiap baris, pseudocode :

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;

Untuk menulis XML, Anda akan menggunakan sesuatu seperti XMLWriter . Untuk membaca data kueri, Anda dapat menggunakan sesuatu seperti PDO atau driver apa pun yang Anda inginkan. Jika kumpulan data besar, pertimbangkan untuk menggunakan kursor untuk membaca data.

Ini bekerja dengan baik, tetapi mentransfer banyak kelebihan data, karena Anda mentransfer n salinan data tabel luar untuk setiap n baris tabel bagian dalam yang terkait dengannya.

Untuk mengurangi kelebihan data yang dipertukarkan, Anda hanya dapat memilih ID untuk tabel luar

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;

... kemudian ketika Anda beralih ke tablea / tableb baru, SELECT sisa barisnya kemudian. Anda mungkin akan menggunakan koneksi kedua untuk melakukan ini sehingga Anda tidak mengganggu set hasil dan status kursor pada koneksi utama tempat Anda membaca baris.

Metode 2:Lakukan semuanya di PostgreSQL

Untuk kumpulan data yang lebih kecil, atau untuk tingkat bagian dalam kumpulan data yang lebih besar, Anda dapat menggunakan dukungan XML PostgreSQL untuk menyusun dokumen XML, mis.:

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;

... tapi sungguh, Anda harus menjadi semacam masokis untuk menulis kode seperti itu. Meskipun itu bisa terbukti cukup cepat.

Untuk memahami kueri Anda harus membaca dokumen XML PostgreSQL . Sintaks aneh diimpikan oleh komite SQL/XML, jangan salahkan kami.

Perhatikan juga bahwa variabel baris banyak digunakan dalam kode di atas agar tetap teratur. a , b dan c dilewatkan sebagai seluruh baris ke lapisan luar kueri. Ini menghindari kebutuhan untuk mengacaukan alias ketika nama bertabrakan. Sintaks (a).a_id , dll, berarti "a_id bidang variabel baris a ". Lihat manual PostgreSQL untuk detailnya.

Di atas menggunakan struktur XML yang lebih baik (lihat komentar di bawah). Jika Anda ingin memancarkan atribut bukan elemen, Anda dapat mengubah XMLFOREST panggilan ke XMLATTRIBUTES panggilan.

Keluaran:

<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>

atau, dicetak cantik:

<?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>

Harap pancarkan XML yang lebih baik

Di samping catatan, menggunakan atribut seperti itu dalam XML tampaknya menggoda, tetapi dengan cepat menjadi sulit dan jelek untuk digunakan. Harap gunakan elemen XML biasa:

  <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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. pg_restore Alternatif - Pencadangan PostgreSQL dan Pemulihan Otomatis dengan ClusterControl

  2. Bagaimana cara mendefinisikan ulang nextval secara global di PostgreSQL?

  3. Konferensi Musim Semi FLOSS UK

  4. Membuat DAG secara Dinamis berdasarkan Baris yang tersedia di Koneksi DB

  5. Penulisan Docker dan Postgres :Nama tidak terselesaikan