sql >> Database teknologi >  >> RDS >> PostgreSQL

PostgreSQL til XML med 3 tabeller

Du har tre niveauer af indlejrede tabeller.

Eksempel på 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:Lav en venstre join, håndter XML i klienten

Den nemmeste måde at håndtere dette på er at lave en venstre join over alle tre borde, ordnet fra yderste til inderste. Derefter gentager du resultatsættet, lukker et element og åbner et andet, når emnet på det niveau ændrer sig.

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;

derefter løkke over de returnerede rækker, og for hver række pseudokode :

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;

For at skrive XML'en skal du bruge noget som XMLWriter . For at læse forespørgselsdataene kan du bruge noget som PDO eller hvilken driver du foretrækker. Hvis datasættet er stort, kan du overveje at bruge en markør til at læse dataene.

Dette fungerer godt, men det overfører masse af overskydende data, da du overfører n kopier af den ydre tabels data for hver n rækker i den indre tabel, der er knyttet til den.

For at reducere de overskydende data, der udveksles, kan du kun vælge ID'erne for de ydre tabeller

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;

... så når du skifter til en ny tablea / tableb, SELECT resten af ​​dens rækker så. Du vil sandsynligvis bruge en anden forbindelse til at gøre dette, så du ikke forstyrrer resultatsættet og markørens tilstand på den hovedforbindelse, du læser rækker fra.

Metode 2:Gør det hele i PostgreSQL

For mindre datasæt, eller for de indre niveauer af større datasæt, kan du bruge PostgreSQL's XML-understøttelse til at konstruere XML-dokumenterne, f.eks.:

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;

... men virkelig, du skal være en slags masochist for at skrive kode på den måde. Selvom det kunne vise sig at være ret hurtigt.

For at forstå forespørgslen skal du læse PostgreSQL XML-dokumenterne . Den skøre syntaks blev opfundet af SQL/XML-udvalget, bebrejde os ikke.

Bemærk også, at rækkevariabler bruges flittigt i ovenstående kode for at holde det organiseret. a , b og c sendes som hele rækker til de ydre lag af forespørgslen. Dette undgår behovet for at rode med aliaser, når navne kolliderer. Syntaksen (a).a_id osv. betyder "a_id felt af rækkevariablen a ". Se PostgreSQL-manualen for detaljer.

Ovenstående bruger en bedre XML-struktur (se kommentarer nedenfor). Hvis du ønsker at udsende attributter ikke elementer, kan du ændre XMLFOREST opkald til XMLATTRIBUTES opkald.

Output:

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

eller smukt trykt:

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

Send venligst bedre XML

På en sidebemærkning virker det fristende at bruge attributter som den i XML, men det bliver hurtigt svært og grimt at arbejde med. Brug venligst normale XML-elementer:

  <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. PostgreSQL-fejl:forespørgselsstrengargumentet for EXECUTE er null

  2. Hvorfor kan jeg ikke oprette forbindelse via jdbc ved hjælp af SQLcl

  3. MySQL - indsæt data fra en anden tabel fusioneret med konstanter

  4. Sådan køres Opret tabel DDL med UDFØR STRAKS i Oracle-databasen