sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL naar XML met 3 tabellen

Je hebt drie niveaus van geneste tabellen.

Voorbeeldgegevens:

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

Methode 1:Doe een left join, behandel XML in de client

De eenvoudigste manier om dit aan te pakken is om een ​​left join uit te voeren over alle drie de tafels, gerangschikt van buitenste naar binnenste. Vervolgens herhaal je de resultatenset, waarbij je het ene element sluit en het andere opent wanneer het onderwerp op dat niveau verandert.

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;

loop dan over de geretourneerde rijen, en voor elke rij, 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;

Om de XML te schrijven zou je zoiets gebruiken als XMLWriter . Om de querygegevens te lezen, kunt u iets als PDO gebruiken of een ander stuurprogramma dat u verkiest. Als de dataset groot is, overweeg dan om een ​​cursor te gebruiken om de data te lezen.

Dit werkt goed, maar het draagt ​​veel over van overtollige gegevens, aangezien u n . overdraagt kopieën van de gegevens van de buitenste tabel voor elke n rijen van de binnenste tabel die ermee verbonden zijn.

Om de overtollige gegevens die worden uitgewisseld te verminderen, kunt u alleen de ID's voor de buitenste tabellen selecteren

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;

... wanneer u vervolgens overschakelt naar een nieuwe tablea / tableb, SELECT de rest van zijn rijen dan. U zult hiervoor waarschijnlijk een tweede verbinding gebruiken, zodat u de resultatenset en de cursorstatus niet verstoort op de hoofdverbinding waarvan u rijen leest.

Methode 2:Doe het allemaal in PostgreSQL

Voor kleinere datasets, of voor de innerlijke niveaus van grotere datasets, kunt u de XML-ondersteuning van PostgreSQL gebruiken om de XML-documenten te construeren, bijvoorbeeld:

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;

... maar echt, je moet een soort masochist zijn om zo'n code te schrijven. Hoewel het redelijk snel zou kunnen blijken te zijn.

Om de query te begrijpen, moet u de PostgreSQL XML-documenten lezen . De maffe syntaxis is bedacht door de SQL/XML-commissie, neem het ons niet kwalijk.

Merk ook op dat rijvariabelen worden veel gebruikt in de bovenstaande code om het georganiseerd te houden. a , b en c worden als hele rijen doorgegeven aan de buitenste lagen van de query. Dit vermijdt de noodzaak om met aliassen te knoeien wanneer namen botsen. De syntaxis (a).a_id , etc, betekent "de a_id veld van de rijvariabele a ". Zie de PostgreSQL-handleiding voor details.

Het bovenstaande maakt gebruik van een betere XML-structuur (zie opmerkingen hieronder). Als u attributen en geen elementen wilt uitzenden, kunt u de XMLFOREST . wijzigen oproepen naar XMLATTRIBUTES oproepen.

Uitgang:

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

of, mooi bedrukt:

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

Stuur een betere XML uit

Even terzijde, het gebruik van dergelijke attributen in XML lijkt verleidelijk, maar het wordt al snel moeilijk en lelijk om mee te werken. Gebruik gewoon normale XML-elementen:

  <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. Asynchrone database-inserts - python + mysql

  2. PL/MySQL bestaat het?

  3. Waarom kaders gebruiken? Overtuig me dat ik Zend Framework moet uitvinden en gebruiken

  4. PostgreSql INSERT FROM SELECT RETURNING ID