從橋接表的任一側選擇行的正確方法是什麼?
我想對三列進行 SQL 查詢。數據庫有五個表,其中兩個是另外三個的橋表。當我嘗試從表中進行選擇時,我得到了大量不一定具有相關列的行,這對我來說是個問題。我的問題是:如何從三個表中選擇相關列,這些表的行通過橋表關聯?例如:我有通過橋接錶鍊接的學生、班級和教師表。我想從這些表格中選擇學生、他們的班級以及教授這些課程的人。
實際上,我有三個表:
items
、tags
和categorys
以及兩個連接它們的橋表:itemTagBridge
和tagCategoryBridge
。這個想法是,items
表中的項目可以被賦予一個或多個儲存在tags
表中的標籤,並且可以為標籤分配一個或多個儲存在表中的類別categorys
。該itemTagBridge
表具有它正在加入的項目和標籤的tagCategoryBridge
列,並且該表具有它正在加入的標籤和類別的列。我想從數據庫中選擇分配給這些標籤的項目、標籤和類別。我正在使用 SQLite3。我暫時用來解決這個問題的程序叫做 SQLite Studio。數據庫結構的目前狀態如下所示:items: id INTEGER PRIMARY KEY item TEXT tags: id INTEGER PRIMARY KEY tag TEXT categorys: id INTEGER PRIMARY KEY category TEXT itemTagBridge: id INTEGER PRIMARY KEY itemId INTEGER FOREIGN KEY REFERENCES items (id) tagId INTEGER FOREIGN KEY REFERENCES tags (id) tagCategoryBridge: id INTEGER PRIMARY KEY tagId INTEGER FOREIGN KEY REFERENCES tags (id) categoryId INTEGER FOREIGN KEY REFERENCES categorys (id)
我正在測試的數據如下:
items: 1 "Hello World!" 2 "Goodbye World!" tags: 1 "positivity" 2 "hello" 3 "negativity" 4 "goodbye" 5 "helloWorld" 6 "goodByeWorld" categorys: 1 "keyword" 2 "title" itemTagBridge: 1 1 1 2 1 2 3 1 5 4 2 3 5 2 4 6 2 6 tagCategoryBridge: 1 1 1 2 2 1 3 3 1 4 4 1 5 5 2 6 6 2
理論上,我應該能夠通過將橋連接到它們各自的表中來從表項目、標籤和類別表中選擇項目、標籤和類別列,如下所示:
SELECT i.item, t.tag, c.category FROM items as i, tags as t, categorys as c INNER JOIN itemTagBridge AS it ON i.id = it.itemId -- Join 1st side of "it" bridge INNER JOIN itemTagBridge ON t.id= it.tagId -- Join 2nd side of "it" bridge INNER JOIN tagCategoryBridge AS tc ON t.id = tc.tagId -- Join 1st side of "tc" bridge INNER JOIN tagCategoryBridge ON c.id = tc.categoryId; -- Join 2nd side of "tc" bridge
我的問題是上面的 SQL 選擇了 216 行,而它應該選擇的行要少得多。使用時
SELECT DISTINCT
,選擇 6 行。使用時GROUP BY
,也可以選擇最少 6 行。選擇的另一個問題是選擇的行沒有正確匹配(hello 不是標題,hello 是關鍵字,helloWorld 是標題)。6行:
item: tag: category: Goodbye World goodByeWorld keyword Goodbye World goodbye keyword Goodbye World negativity keyword Hello World helloWorld keyword Hello World hello title Hello World positivity title
我一直認為我對連接有嚴重的誤解,不知道在這種情況下適合使用的 SQL 操作,需要使用不同的模式,需要使用不同的數據庫管理系統,或者完全遺漏了一些東西否則有這個問題。我的問題是如何從這個數據庫中選擇項目、標籤和類別,或者如果這是不可能的、非最佳的或不切實際的,那麼更好的解決方案是什麼?
感謝您的所有幫助,我是 SQL 新手,我已經在這裡迷路了大約一周,看不到盡頭。
編輯:
DDL
-- Drop tables DROP TABLE IF EXISTS itemTagBridge; DROP TABLE IF EXISTS tagCategoryBridge; DROP TABLE IF EXISTS items; DROP TABLE IF EXISTS tags; DROP TABLE IF EXISTS categorys; -- Create tables CREATE TABLE items( id INTEGER PRIMARY KEY, item TEXT); CREATE TABLE tags( id INTEGER PRIMARY KEY, tag TEXT); CREATE TABLE categorys( id INTEGER PRIMARY KEY, category TEXT); CREATE TABLE itemTagBridge( id INTEGER PRIMARY KEY, itemId INTEGER REFERENCES items (id), tagId INTEGER REFERENCES tags (id)); CREATE TABLE tagCategoryBridge( id INTEGER PRIMARY KEY, tagId INTEGER REFERENCES tags (id), categoryId INTEGER REFERENCES categorys (id));
DML
-- Insert test data into tables INSERT INTO items (item) VALUES ("Hello World!"), ("Goodbye World!"); INSERT INTO tags (tag) VALUES ("positivity"), ("hello"), ("negativity"), ("goodbye"), ("helloWorld"), ("goodByeWorld"); INSERT INTO categorys (category) VALUES ("keyword"), ("title"); INSERT INTO itemTagBridge (itemId, tagId) Values (1, 1), (1, 2), (1, 5), (2, 3), (2, 4), (2, 6); INSERT INTO tagCategoryBridge (tagId, categoryId) VALUES (1, 1), (2, 1), (3, 1), (4, 1), (5, 2), (6, 2);
為了解決您的問題,我執行了以下操作:
建構了您的表格和數據,如這裡的小提琴所示。也顯示在這個答案的底部。
對於您的連接表(或關聯實體),我將兩個連接欄位組合在一起 - 由於此處和此處列出的原因
PRIMARY KEY
,單獨是多餘的。(這也是我過去常犯的錯誤!:-))。INTEGER PRIMARY KEY
在 SQLite 3.8 上,我執行了這個查詢(小提琴):
SELECT i.item, t.tag, c.category FROM items i JOIN itemTagBridge itb ON i.id = itb.itemID JOIN tags t ON itb.tagID = t.id JOIN tagCategoryBridge tcb ON itb.tagId = tcb.tagId JOIN categorys c ON tcb.categoryId = c.id;
結果:
item tag category Hello World! positivity keyword Hello World! hello keyword Hello World! helloWorld title Goodbye World negativity keyword Goodbye World goodbye keyword Goodbye World goodByeWorld title 6 rows
這似乎是您想要的結果。
然後我執行了你自己的查詢(小提琴)
SELECT i.item, t.tag, c.category FROM items as i, tags as t, categorys as c INNER JOIN itemTagBridge AS it ON i.id = it.itemId -- Join 1st side of "it" bridge INNER JOIN itemTagBridge ON t.id= it.tagId -- Join 2nd side of "it" bridge INNER JOIN tagCategoryBridge AS tc ON t.id = tc.tagId -- Join 1st side of "tc" bridge INNER JOIN tagCategoryBridge ON c.id = tc.categoryId; -- Join 2nd side of "tc" bridge
它確實產生了 216 個結果,6 組 36 個相同的結果。
36 = 6 * 6,這是您在加入表格時擁有的欄位數 - 所以您似乎
CROSS JOIN
在它們之間進行某種操作,並且 36 * 6 = 216,因此您似乎加入標籤 3 次(6 條記錄在標籤)與其他表和您的連接表都有標籤。您要做的是通過連接表加入
item
到。您似乎加入了您的橋接表兩次,而不是僅一次,這導致了我們在您的 216 條記錄結果集中看到的乘法效應。tag``category
使用您的表結構,您要做的就是簡單地通過 id 連接,作為表之間的連結欄位。在這最後的小提琴中,我逐行剖析了我的查詢和您的查詢。過去我發現這是一種非常有效的學習方法。HTH,歡迎來到論壇!
================= 表的 DDL 和 DML ===================
將來,根據評論中的要求,請以 DDL 和 DML 的形式提供表格和數據 - 幫助我們為您提供幫助!我的個人資料上有一些關於在這個論壇上提問的文章 - 你可能想看看?
CREATE TABLE items ( id INTEGER PRIMARY KEY AUTOINCREMENT, item TEXT ); CREATE TABLE tags ( id INTEGER PRIMARY KEY AUTOINCREMENT, tag TEXT ); CREATE TABLE categorys ( id INTEGER PRIMARY KEY AUTOINCREMENT, category TEXT ); CREATE TABLE itemTagBridge ( itemId INTEGER, tagId INTEGER, PRIMARY KEY (itemId, tagId), FOREIGN KEY (itemID) REFERENCES items (id), FOREIGN KEY (tagId) REFERENCES tags (id) ); CREATE TABLE tagCategoryBridge ( tagId INTEGER, categoryId INTEGER, PRIMARY KEY (tagId, categoryId), FOREIGN KEY (tagId) REFERENCES tags (id), FOREIGN KEY (categoryId) REFERENCES categorys (id) ); INSERT INTO items (item) VALUES ('Hello World!'), ('Goodbye World'); INSERT INTO categorys (category) VALUES ('keyword'), ('title'); INSERT INTO tags (tag) VALUES ('positivity'), ('hello'), ('negativity'), ('goodbye'), ('helloWorld'), ('goodByeWorld'); INSERT INTO itemTagBridge VALUES(1, 1), (1, 2), (1, 5), (2, 3), (2, 4), (2, 6); INSERT INTO tagCategoryBridge VALUES (1, 1), (2, 1), (3, 1), (4, 1), (5, 2), (6, 2);