Considere as seguintes tabelas
Device
--------
id
name
type
--------
components
--------
id INT
type VARCHAR
--------
Manufacturers
-------------
id INT
name VARCHAR
country VARCHAR
-------------
Device_components
-----------------
deviceid REFERENCES Devices(id)
componentid REFERENCES Components(id)
-----------------
Component_Manufacturers
-----------------------
componentid REFERENCES Components(id)
manufacturerid REFERENCES Manufacturers(id)
-----------------------
Eu quero consultar o banco de dados para retornar algo assim:
{
"id": 1,
"name": "phone",
"components": [
{
"id": 1,
"type": "screen",
"manufacturers": [
{
"id": 1,
"name": "a",
"country": "Germany"
}
]
},
{
"id": 2,
"type": "keyboard",
"manufacturers": [
{
"id": 1,
"name": "a",
"country": "UK"
}
]
}
]
}
Até agora estou selecionando cada tabela individualmente e depois montando o objeto JSON na minha aplicação.
Aqui estão alguns dados de exemplo:
CREATE TABLE IF NOT EXISTS Devices
(
ID SERIAL PRIMARY KEY NOT NULL,
NAME VARCHAR(30) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS Components
(
ID SERIAL PRIMARY KEY NOT NULL,
NAME VARCHAR(30) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS Manufacturers
(
ID SERIAL PRIMARY KEY NOT NULL,
NAME VARCHAR(30) UNIQUE NOT NULL,
COUNTRY VARCHAR(40)
);
CREATE TABLE IF NOT EXISTS Device_components
(
DeviceID INT REFERENCES Devices(ID),
ComponentID INT REFERENCES Components(ID)
);
CREATE TABLE IF NOT EXISTS Component_manufacturers
(
ComponentID INT REFERENCES Components(ID),
ManufacturerID INT REFERENCES Manufacturers(ID)
);
INSERT INTO Devices (NAME) VALUES ('phone');
INSERT INTO Devices (NAME) VALUES ('tablet');
INSERT INTO Devices (NAME) VALUES ('pc');
INSERT INTO Components (NAME) VALUES ('mouse');
INSERT INTO Components (NAME) VALUES ('camera');
INSERT INTO Components (NAME) VALUES ('screen');
INSERT INTO Manufacturers (NAME,Country) VALUES ('foo','france');
INSERT INTO Manufacturers (NAME,Country) VALUES ('bar','spain');
INSERT INTO Manufacturers (NAME,Country) VALUES ('baz','germany');
INSERT INTO Device_components VALUES (1,2);
INSERT INTO Device_components VALUES (1,3);
INSERT INTO Device_components VALUES (2,2);
INSERT INTO Device_components VALUES (2,3);
INSERT INTO Device_components VALUES (3,1);
INSERT INTO Device_components VALUES (3,2);
INSERT INTO Device_components VALUES (3,3);
INSERT INTO Component_manufacturers VALUES (1,1);
INSERT INTO Component_manufacturers VALUES (1,2);
INSERT INTO Component_manufacturers VALUES (1,3);
INSERT INTO Component_manufacturers VALUES (2,2);
INSERT INTO Component_manufacturers VALUES (3,3);
Tudo bem, parece que você deseja criar um gráfico a partir de uma árvore de junção. Isso é uma coisa bastante natural de querer fazer.
Não é tão fácil como deveria ser em Pg, principalmente por causa da falta de suporte para apelidos de coluna no
record
pseudo-tipo.Aqui está o que eu criei:
A ideia geral aqui é, em todos os níveis de aninhamento de objetos em que você está produzindo uma matriz de objetos, use
json_agg
em um arquivogroup_by
. Ajson_agg
função chama implicitamenterow_to_json
para transformar um tipo de linha em json. NaSELECT
cláusula, especifique aliases para as colunas sintéticas para que os nomes das chaves json estejam corretos quando a linha for alimentada no nível externo.Como o nível externo não é agregado, use
row_to_json
sobre uma subconsulta em vez de usarjson_agg
. Se você deseja um único resultado json em vez de um conjunto de linhas json, pode alterarrow_to_json
parajson_agg
no nível externo.Eu testei apenas no 9.3, pois é o que instalei e o sqlfiddle parece estar tendo alguns problemas.
Atualização : Infelizmente
json_agg
não existe no 9.2 , foi adicionado no 9.3. No entanto, este é um caso bastante simples que você pode usararray_agg
em vez disso, então isso deve funcionar em 9.2 :Idealmente, o PostgreSQL suportaria esse tipo de consulta de forma mais natural, sem as subconsultas, mas acho que precisaríamos de um novo tipo de junção, ou pelo menos algumas funções para usar com consultas laterais. De qualquer maneira , tudo planeja um plano de consulta civilizado (embora seja melhor com índices adequados):