Postgresql
將多對多連接的右側轉換為數組
在多對多關係上使用連接時,結果將拆分為多行。我想做的是將連接的右側轉換為數組,因此結果是一行。
以 3 個表為例:
CREATE TABLE items ( id serial primary key, title text ); CREATE TABLE tags ( id serial primary key, title text ); CREATE TABLE items_tags ( item_id int references items(id), tag_id int references tags(id), primary key (item_id, tag_id) );
當選擇帶有標籤的項目時,我可以這樣做:
SELECT i.id, i.title, i.title FROM items i INNER JOIN items_tags it ON it.item_id = i.id INNER JOIN tags t ON t.id = it.tag_id;
結果將如下所示:
(1, "item n1", "sport") (1, "item n1", "soccer") (2, "item n2", "adventure") (2, "item n2", "mountain climbing") (2, "item n2", "sport") (2, "item n2", "nature")
我想要的是這樣的:
(1, "item n1", ["sport", "soccer"]) (2, "item n2", ["adventure", "mountain climbing", "sport" , "nature"])
聚合大多數行
在查詢所有或大多數項目時,首先從“許多”表聚合行並稍後連接通常要快得多:
SELECT id, i.title AS item_title, t.tag_array FROM items i JOIN ( -- or LEFT JOIN ? SELECT it.item_id AS id, array_agg(t.title) AS tag_array FROM items_tags it JOIN tags t ON t.id = it.tag_id GROUP BY it.item_id ) t USING (id);
LEFT [OUTER] JOIN
如果可以有沒有標籤的項目,則在外部查詢中使用- 這將被排除在[INNER] JOIN
.由於這不會增加連接中的行,因此我們不需要
GROUP BY
在外部SELECT
.在聚合之前加入也會在列表中出現多個 1:n 表時失控
FROM
(在這種簡單的情況下不是這樣)。看:聚合幾行
對於一小部分行,使用
LATERAL
帶有ARRAY 建構子的連接:SELECT id, title AS item_title, t.tag_array FROM items i, LATERAL ( -- this is an implicit CROSS JOIN SELECT ARRAY ( SELECT t.title FROM items_tags it JOIN tags t ON t.id = it.tag_id WHERE it.item_id = i.id ) AS tag_array ) t;
由於 ARRAY 建構子總是產生一行(如果子查詢為空,則為空數組 - 結果的細微差別!),
LEFT JOIN LATERAL (...) ON true
這裡不需要。看:在旁邊
您的查詢中有錯字。第 3 列將是
t.title
. 我為您的原始(未聚合)查詢添加了別名以澄清:SELECT i.id, i.title AS item_title, t.title AS tag_title FROM items i JOIN items_tags it ON it.item_id = i.id JOIN tags t ON t.id = it.tag_id;
“id”或“title”通常不是很獨特且不是很有用的標識符。看: