PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL do XML z 3 tabelami

Masz trzy poziomy zagnieżdżonych tabel.

Przykładowe dane:

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

Metoda 1:Wykonaj lewe sprzężenie, obsługuj XML w kliencie

Najprostszym sposobem poradzenia sobie z tym jest wykonanie lewego sprzężenia dla wszystkich trzech tabel, uporządkowanych od najbardziej zewnętrznego do wewnętrznego. Następnie iterujesz w dół zestawu wyników, zamykając jeden element i otwierając inny, gdy temat na tym poziomie się zmieni.

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;

następnie przejdź do zwróconych wierszy, a dla każdego wiersza pseudokod :

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;

Aby napisać XML, użyj czegoś takiego jak XMLWriter . Aby odczytać dane zapytania, możesz użyć czegoś takiego jak PDO lub innego preferowanego sterownika. Jeśli zestaw danych jest duży, rozważ użycie kursora do odczytania danych.

Działa to dobrze, ale przenosi dużo nadmiaru danych, ponieważ przesyłasz n kopie danych tabeli zewnętrznej dla każdego n wiersze tabeli wewnętrznej z nią powiązanej.

Aby zmniejszyć nadmiar wymienianych danych, możesz wybrać tylko identyfikatory dla tabel zewnętrznych

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;

... następnie po przełączeniu na nową tabelęa / tableb, SELECT pozostałe jego rzędy. Prawdopodobnie użyjesz do tego drugiego połączenia, aby nie zakłócać zestawu wyników i stanu kursora na głównym połączeniu, z którego odczytujesz wiersze.

Metoda 2:Zrób to wszystko w PostgreSQL

W przypadku mniejszych zestawów danych lub wewnętrznych poziomów większych zestawów danych można użyć obsługi XML PostgreSQL do tworzenia dokumentów XML, np.:

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;

... ale tak naprawdę, żeby pisać taki kod, trzeba być jakimś masochistą. Chociaż może się to okazać dość szybkie.

Aby zrozumieć zapytanie musisz przeczytać dokumenty XML PostgreSQL . Ta zwariowana składnia została wymyślona przez komisję SQL/XML, nie obwiniajcie nas.

Pamiętaj też, że zmienne wierszowe są intensywnie używane w powyższym kodzie, aby utrzymać porządek. a , b i c są przekazywane jako całe wiersze do zewnętrznych warstw zapytania. Pozwala to uniknąć grzebania w aliasach w przypadku kolizji nazw. Składnia (a).a_id itd. oznacza „a_id pole zmiennej wierszowej a ". Więcej informacji znajdziesz w podręczniku PostgreSQL.

Powyższe wykorzystuje lepszą strukturę XML (patrz komentarze poniżej). Jeśli chcesz emitować atrybuty, a nie elementy, możesz zmienić XMLFOREST wywołania XMLATTRIBUTES połączeń.

Wyjście:

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

lub ładnie wydrukowane:

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

Proszę emitować lepszy kod XML

Na marginesie, używanie takich atrybutów w XML wydaje się kuszące, ale szybko staje się trudne i brzydkie w obsłudze. Proszę używać zwykłych elementów 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL wybierz elementy, w których suma pola jest mniejsza niż N

  2. psql:FATAL:nie można otworzyć bazy plików/11951/11717:system plików tylko do odczytu

  3. Zaktualizuj kolumnę tabeli o kolumnę innej tabeli w PostgreSQL

  4. Cayenne, Postgres:generowanie klucza podstawowego

  5. Błąd:Uwierzytelnianie peera nie powiodło się dla postgres użytkownika podczas próby uruchomienia pgsql działającego z szynami