「短」版查看從同一個表
兩個外鍵引用的表我有兩個表:image
和item
。項目由兩個圖像組成:讓我們稱它們爲left
和right
(項目的GUI可以是例如具有並排的兩個圖像的畫布)。我正在設置關於圖像的報告,顯示哪些項目「使用」它們。
+------------+ +------------+
| image | | item |
+------------+ +------------+
| id <------------+ | id |
| name | | | name |
+------------+ +-------- im_left |
+-------- im_right |
+------------+
雖然瑣碎找出查詢,如果一個項目只有一個單一的參考圖像,我有這樣的延伸到了「雙重引用」的情況下,特別是當一個項目引用相同的圖像兩次麻煩(鑑於我的業務限制,完全合法的情況)。
到現在爲止,我使用了兩個帶有別名的LEFT OUTER JOIN
s來使用左右列將圖像連接到項目。但是當左圖和右圖使用相同的圖像時,這個構造失敗(我無法真正解釋結果,如下所示)。
由於這是數據庫設計中的一種非常常見的模式,在這種情況下,您將如何設計一個視圖,以顯示每個圖像及其使用的每個項目以及它引用的列。
例如
- IMAGE_1用於通過ITEM_1和ITEM_2(左)和ITEM_3(右)
- IMAGE_2用於通過無(左)和ITEM_4(右)
- IMAGE_3用於通過item_5和item_6(左)和item_6(右)
長版(可能過於本地化,但顯示我的考驗和具體的問題)。
這裏是我的2代表的定義:
CREATE TABLE image (
id serial PRIMARY KEY,
name text
);
INSERT INTO image(name) VALUES ('image 1');
INSERT INTO image(name) VALUES ('image 2');
INSERT INTO image(name) VALUES ('image 3');
CREATE TABLE item (
id serial PRIMARY KEY,
name text,
im_left int,
FOREIGN KEY (im_left) REFERENCES image(id),
im_right int,
FOREIGN KEY (im_right) REFERENCES image(id)
);
INSERT INTO item(name,im_left,im_right) VALUES ('item 1',1,2);
INSERT INTO item(name,im_left,im_right) VALUES ('item 2',1,3);
INSERT INTO item(name,im_left,im_right) VALUES ('item 3',2,3);
直到今天,我就是用這個查詢來建立我的觀點:
CREATE VIEW imagev_v1 AS (
SELECT image.id, image.name,
array_agg(li.id) AS left_ids,
array_agg(li.name) AS left_names,
array_agg(ri.id) AS right_ids,
array_agg(ri.name) AS right_names
FROM image
LEFT OUTER JOIN item AS li ON li.im_left=image.id
LEFT OUTER JOIN item AS ri ON ri.im_right=image.id
GROUP BY image.id, image.name
ORDER BY name ASC
);
而且它相當奏效:
SELECT * FROM imagev_v1;
id | name | left_ids | left_names | right_ids | right_names
----+---------+-------------+---------------------+-------------+---------------------
1 | image 1 | {1,2} | {"item 1","item 2"} | {NULL,NULL} | {NULL,NULL}
2 | image 2 | {3} | {"item 3"} | {1} | {"item 1"}
3 | image 3 | {NULL,NULL} | {NULL,NULL} | {2,3} | {"item 2","item 3"}
(3 rows)
直到我添加了一個引用左側和右側列中相同圖像的鬼祟道具:
INSERT INTO item(name,im_left,im_right) VALUES ('item 4',3,3);
SELECT * FROM imagev_v1;
id | name | left_ids | left_names | right_ids | right_names
----+---------+----------+------------------------------+-------------+------------------------------
1 | image 1 | {1,2} | {"item 1","item 2"} | {NULL,NULL} | {NULL,NULL}
2 | image 2 | {3} | {"item 3"} | {1} | {"item 1"}
3 | image 3 | {4,4,4} | {"item 4","item 4","item 4"} | {2,3,4} | {"item 2","item 3","item 4"}
(3 rows)
第三個結果行很奇怪,至少可以說,但我無法解釋行爲。
我試過的觀點,其工作的另一個版本,但沒有表現出參考的原點(圖像是否由im_left
或im_right
列引用)的能力:
CREATE VIEW imagev_v2 AS (
SELECT image.id, image.name,
array_agg(item.id) AS item_ids,
array_agg(item.name) AS item_names
FROM image
LEFT OUTER JOIN item ON item.im_left=image.id OR item.im_right=image.id
GROUP BY image.id, image.name
ORDER BY name ASC
);
SELECT * FROM image_v2 ;
id | name | item_ids | item_names
----+---------+----------+------------------------------
1 | image 1 | {1,2} | {"item 1","item 2"}
2 | image 2 | {1,3} | {"item 1","item 3"}
3 | image 3 | {2,3,4} | {"item 2","item 3","item 4"}
(3 rows)
謝謝你閱讀到這一點,現在你有權看到實際的問題:我怎樣才能寫imagev_v3
這是正確的在任何時候(不像image_v1
),雖然沒有遭受「原產地損失」的問題,image_v2
有?
請注意,我使用PostgreSQL 8.4,但我認爲它應該是非常不相關的。
Aaahh,所以此案的事情是的伎倆!非常感謝您的洞察力(和時間)。 – Tibo 2013-04-08 14:27:42
案例解決了這麼多問題.... – 2013-04-08 15:04:13