Máte tři úrovně vnořených tabulek.
Ukázková 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');
Metoda 1:Proveďte levé spojení, zpracujte XML v klientovi
Nejjednodušší způsob, jak to zvládnout, je provést levé spojení nad všemi třemi tabulkami v pořadí od nejvzdálenější k nejvnitřnější. Potom iterujete sadu výsledků, zavřete jeden prvek a otevřete další, kdykoli se předmět na dané úrovni změní.
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;
pak opakujte vrácené řádky a pro každý řádek pseudokód :
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;
K zápisu XML byste použili něco jako XMLWriter
. Pro čtení dat dotazu můžete použít něco jako PDO nebo jakýkoli ovladač, který preferujete. Pokud je datová sada velká, zvažte použití kurzoru ke čtení dat.
Funguje to dobře, ale přenáší to hodně přebytečných dat, protože přenesete n
kopie dat vnější tabulky pro každý n
řádků vnitřní tabulky, která je s ním spojena.
Pro snížení nadměrného množství vyměňovaných dat můžete vybrat pouze ID pro vnější tabulky
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 když přepnete na novou tabulku / tabulku, SELECT
zbytek jeho řad pak. Pravděpodobně k tomu použijete druhé připojení, abyste nenarušili sadu výsledků a stav kurzoru na hlavním připojení, ze kterého čtete řádky.
Metoda 2:Udělejte to všechno v PostgreSQL
Pro menší datové sady nebo pro vnitřní úrovně větších datových sad můžete ke konstrukci XML dokumentů použít podporu PostgreSQL XML, např.:
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 opravdu musíte být nějaký masochista, abyste mohli psát takový kód. I když by se to mohlo ukázat jako docela rychlé.
Abyste porozuměli dotazu budete si muset přečíst dokumenty PostgreSQL XML . Ta bláznivá syntaxe byla vymyšlena výborem SQL/XML, neobviňujte nás.
Všimněte si také, že řádkové proměnné se ve výše uvedeném kódu hojně používají, aby byl organizován. a
, b
a c
jsou předány jako celé řádky vnějším vrstvám dotazu. Vyhnete se tak nutnosti zacházet s aliasy, když se jména srazí. Syntaxe (a).a_id
, atd., znamená „a_id
pole řádkové proměnné a
Podrobnosti naleznete v příručce PostgreSQL.
Výše uvedené používá lepší strukturu XML (viz komentáře níže). Pokud chcete emitovat atributy, nikoli prvky, můžete změnit XMLFOREST
volání XMLATTRIBUTES
hovory.
Výstup:
<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>
nebo pěkně vytištěné:
<?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>
Vyšlete prosím lepší XML
Na okraj, použití atributů jako je tento v XML se zdá lákavé, ale rychle se s ním pracuje obtížně a ošklivě. Použijte prosím normální prvky 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>