我有以下表格:
CREATE TABLE sequence (
id serial PRIMARY KEY
-- ...other sequence data
)
CREATE TABLE sound (
id serial PRIMARY KEY
-- ...other sound data
)
CREATE TABLE layer (
id serial PRIMARY KEY,
index smallint NOT NULL,
sequence integer NOT NULL REFERENCES sequence (id)
)
CREATE TABLE layerSound (
id serial PRIMARY KEY,
index smallint NOT NULL,
layer integer NOT NULL REFERENCES layer (id),
sound integer NOT NULL REFERENCES sound (id)
)
所以我有序列。每个序列都有很多层。每一层 有很多layerSounds。每个layerSound都附加一个声音。
我想编写一个可以选择特定序列的查询(返回JSON) 通过它的ID,然后加入:
例如:
{
sequence: 3,
layers: [1, 2],
layerSounds: [
{ layer: 1, sounds: [1, 2] },
{ layer: 2, sounds: [2, 3] }
],
sounds: [
{ id: 1, foo: "bar" },
{ id: 2, foo: "baz" },
{ id: 3, foo: "blah" }
]
}
因此,目标是仅将完整的声音数据写入一次,然后再写入layerSounds.sounds 数组只有声音ID。所以声音数据不会重复。
到目前为止,我的方法是选择序列,然后分别聚合其他表。我按顺序ID对每个进行分组,然后针对外部查询加入一次。
虽然这有效,但我注意到我必须在每个JOIN查询中重复连接才能始终按sequenceId进行分组。
因此,要通过sequenceId对layerSounds进行分组,我将图层连接到layerSound以发声。然后,我再次进行完全相同的连接,以计算此序列使用的所有声音。我在下面提到了这个问题。
我的问题是,有没有办法改善这个查询?这种方法有问题吗?或者正在重新使用这样的连接?
感谢您的时间。
查询:
SELECT
sequence.id,
layers.ids AS layers,
layerSounds.ids AS layerSounds,
sounds.ids AS sounds
FROM sequence
JOIN (
SELECT
sequence,
json_agg(id) AS ids
FROM layer
GROUP BY sequence
) layers ON layers.sequence = sequence.id
JOIN (
SELECT
sequence,
json_agg(layerSounds) AS ids
FROM layer
JOIN (
SELECT
layerSound.layer,
json_agg(sound.id) AS ids
FROM layerSound
JOIN sound
ON sound.id = layerSound.sound
GROUP BY layerSound.layer
) layerSounds ON layerSounds.layer = layer.id
GROUP BY sequence
) layerSounds ON layerSounds.sequence = sequence.id
JOIN (
SELECT
sequence,
json_agg(DISTINCT sound.id) AS ids
FROM layer
JOIN layerSound
ON layerSound.layer = layer.id
JOIN sound
ON sound.id = layerSound.sound
GROUP BY sequence
) sounds ON sounds.sequence = sequence.id
答案 0 :(得分:1)
您绝对可以简化查询。我认为这是一个简化:
SELECT s.id, l.ids AS layers, ls.ids AS layerSounds,
so.ids AS sounds
FROM sequence s JOIN
(SELECT l.sequence, json_agg(l.id) AS ids,
json_agg(ls)
FROM layer l JOIN
(SELECT ls.layer, json_agg(ls.sound) AS ids
FROM layerSound ls
GROUP BY ls.layer
) ls
ON ls.layer = l.id
GROUP BY l.sequence
) l
ON l.sequence = s.id JOIN
(SELECT l.sequence,
json_agg(DISTINCT ls.sound) AS ids
FROM layer l JOIN
layerSound ls
ON ls.layer = l.id
GROUP BY l.sequence
) so
ON so.sequence = s.id;
一个重要的观察结果是,您无需加入sounds
,因为信息位于layerSound
。
第一个子查询结合了您的版本中的前两个子查询。在Postgres中,可能有一种方法可以将图层声音JSON数组合并到一个数组中(可能使用Postgres数组作为中介)。但这将最后一个列表作为一个单独的子查询。