[英]MySQL database design for image options relationships
我有兩個表, images和image_data ,這是我的image_data表的一個例子。
image_id | slide_id | language_id | type |
101 | 1 | 1 | CQ |
101 | 2 | NULL | NULL |
56 | 5 | 1 | TN |
56 | NULL | 2 | NULL |
所以基本上,每個圖像都有不同的選項,我想知道實現這個的最好方法..因為我有一種感覺,我這樣做是錯誤的。
有了這個,我可以運行一個查詢來使用GROUP_CONCAT()
將多行中的值轉換為單個連接字符串。
image_id | slide_id | language_id | type |
101 | 1,2 | 1 | CQ |
56 | 5 | 1,2 | TN |
這很好,但我現在正在做的方式的問題是..看起來用我的后端系統更新行真的很難。
因此,根據我的查詢,我可以根據數據庫確定要檢查哪些數據庫,因為自從我連接它以來我將它全部放在一行中。 但是現在它就像..當我點擊“保存”並更新行時,我會更新哪一行? 相同的圖像ID可以有多於一行,所以如何更新正確的行,依此類推。
如果我檢查了圖像#101的另一張幻燈片,那么我需要為它創建一個新行。 如果之后我想添加另一個language_id,那么我需要確保不添加新行,因為一個存在NULL值,並且只用新語言id替換NULL值。
它看起來真的很復雜,並且有很多因素,使用這種方法真的很難編程。
最好的方法是什么? 任何建議都非常感謝。
謝謝!
您需要做的是在images
和slides
/ languages
/ types
表之間實現N:M(多對多)關系,以便您的設計更加規范化(一個地方就是一個事實)。
可以這樣想:一個image
可以有多個slides
,一個slide
可以是多個images
的選項。 - 這是N:M的關系。 語言和類型也是如此。
你需要做的是擺脫你的image_data
表,它包含所有實體之間的選項,而是有三個獨立的交叉引用表。 以下是您對其進行建模的方法:
基表:
圖像 (image_id [PK],...)
幻燈片 (slide_id [PK],slide_name,...)
語言 (language_id [PK],language_name,...)
types (type_name [PK],...)
交叉參考表:
images_has_slides (image_id [PK],slide_id [PK])
images_has_languages (image_id [PK],language_id [PK])
images_has_types (image_id [PK],type_name [PK])
如何看待ER:
使用這種類型的設計,您不必處理NULL
值或找出要更新的行,因為您現在只在一個地方有一個事實 。 要獲得所有選項,您仍然需要像這樣執行GROUP_CONCAT()
:
SELECT
a.*,
GROUP_CONCAT(c.slide_name) AS slides,
GROUP_CONCAT(e.language_name) AS languages,
GROUP_CONCAT(f.type_name) AS types
FROM
images a
LEFT JOIN
images_has_slides b ON a.image_id = b.image_id
LEFT JOIN
slides c ON b.slide_id = c.slide_id
LEFT JOIN
images_has_languages d ON a.image_id = d.image_id
LEFT JOIN
languages e ON d.language_id = e.language_id
LEFT JOIN
images_has_types f ON a.image_id = f.image_id
GROUP BY
a.image_id
然后,要更新圖像選項,您將在交叉引用表上使用INSERT
和DELETE
:
假設您想要為圖像添加兩種語言,您可以這樣做
INSERT INTO images_has_languages (image_id, language_id)
VALUES (101, 4), (101, 5);
上面的查詢將id為4
和5
語言添加到id為101
的圖像中。
要刪除選項(取消選中表單) - 假設您要從圖像中刪除2張幻燈片
DELETE FROM images_has_slides WHERE image_id = 101 AND slide_id IN (3,6)
這將從ID為101
的圖像中刪除ID為3
和6
幻燈片。
因此,在您的應用程序中,您可以根據用戶是否取消選中或檢查圖像表單中的值來確定是否需要插入/刪除查詢。
您需要規范化架構。
images
表: CREATE TABLE images (
image_id integer,
image_name varchar(100),
PRIMARY KEY(image_id)
);
slides
: CREATE TABLE slides (
slide_id integer,
image_id integer,
slide_name varchar(100),
PRIMARY KEY(slide_id)
);
image_types
和image_languages
。 我希望你理解邏輯。 並確保添加適當的FOREIGN KEY
約束。 此外,在下級表的image_id
列上CREATE INDEX
是個好主意。
現在,相關表中每個參數有1行。 管理內容應該很簡單:在選擇某些功能時INSERT
新記錄,並在取消選擇這些功能時DELETE
它們。 查詢(基於概述的2個表)應該是:
SELECT i.image_id, i.image_name,
group_concat(s.slide_id) AS slides
FROM images i
LEFT JOIN slides s USING (image_id)
GROUP BY i.image_id;
一些說明:
GROUP BY
僅image_id
,因為它是一個PRIMARY KEY
的的iamges
,因此它會保證單行groupping; slide_id
(也是language_id
, type_id
和其他),您可以在下級表中使用2字段主鍵,如PRIMARY KEY (image_id, slide_id)
。 編輯:
關於多對多關系的說明。 如果你碰巧有2組相關數據,比如images
可以有很多slides
而且slide_id
可以被很多image_id
共享,那么你需要一個額外的表:
CREATE TABLE images (
image_id integer,
image_name varchar(100),
PRIMARY KEY(image_id)
);
CREATE TABLE slides (
slide_id integer,
slide_name varchar(100),
PRIMARY KEY(slide_id)
);
CREATE TABLE image_slides (
image_id integer,
slide_id integer,
create_dt timestamp,
PRIMRY KEY (image_id, slide_id)
);
你試過拆分表嗎? 如果您為幻燈片和語言創建單獨的表,並將類型保留在與圖像ID相同的表中,則可以使用該表來創建列表。 然后,您可以使用外鍵優化數據庫,這樣您就不會受到太大的性能影響。
這就是我的意思:
圖像數據表:兩列,image_id和image_type(類型是保留字)。 Imageid是主鍵,因此沒有重復項(假設您只想為每個圖像使用一種類型)
圖像語言表:兩列,圖像ID和image_language。 兩者都是主鍵,因此您不會在同一圖像ID上復制語言,但圖像ID可以包含多種語言。 圖像ID中的主鍵鏈接到圖像數據表中的主鍵
圖像幻燈片表:兩列,圖像ID和幻燈片編號。 與上面相同(兩個主鍵,關系等)
這樣你就可以獲得所有數據:
SELECT d.image_id, d.image_type, l.image_language, s.slide_number FROM image_data d LEFT JOIN image_language l ON d.image_id = l.image_id LEFT JOIN image_slide s ON s.image_id = s.image_id
左連接確保即使沒有足夠的語言或幻燈片,也無論如何都會顯示所有項目ID。 它將為您創建一個“矩陣”,每個圖像和每種語言以及它適用的每個幻燈片都有一行。 例如,如果您的圖像具有西班牙語和英語作為其語言和4個幻燈片,您將獲得8個條目:每種語言的每張幻燈片一個。
我不知道這是否一定能解決這個問題,但是如果仍然讓數據庫為你做一些工作,它會更容易控制數據庫中的確切內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.