PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

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 в клиента

Най-лесният начин да се справите с това е да направите ляво съединение върху всичките три таблици, подредени от най-външната към най-вътрешната. След това итерирате набора от резултати, затваряйки един елемент и отваряйки друг всеки път, когато темата на това ниво се промени.

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 редове от вътрешната таблица, свързана с него.

За да намалите излишните обменени данни, можете да изберете само идентификаторите за външните таблици

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;

... тогава, когато превключите към нова таблицаa / tableb, SELECT тогава останалите му редове. Вероятно ще използвате втора връзка, за да направите това, за да не нарушите набора от резултати и състоянието на курсора на основната връзка, от която четете редове.

Метод 2:Направете всичко в PostgreSQL

За по-малки набори от данни или за вътрешни нива на по-големи набори от данни можете да използвате XML поддръжката на PostgreSQL, за да конструирате 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;

... но наистина трябва да си някакъв мазохист, за да пишеш такъв код. Въпреки че може да се окаже доста бързо.

За да разберете заявката ще трябва да прочетете PostgreSQL XML документите . Шантавият синтаксис беше измислен от комисията по SQL/XML, не ни обвинявайте.

Също така имайте предвид, че променливите на ред се използват силно в горния код, за да го поддържат организиран. a , b и 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да актуализирате масив в PostgreSQL

  2. plpgsql CREATE FUNCTION синтактична грешка при или близо до 'CREATE'

  3. Използване на ADO във VBA за свързване с PostgreSQL

  4. Hibernate 4 и Postgres:Как да създадете последователност на таблица?

  5. Създаване на копие на база данни в PostgreSQL