当有多个表可供选择时,存储收藏夹的最有效方法是什么。
例如:您有一个用户(ID,名称,...),食物(ID,卡路里......),鸡尾酒(ID,酒精,...)和糖果(ID,名称,.. 。),用户可以从这些表中收藏多个元素。解决这个问题的最佳方法是什么。
我的想法是创建一个多对多的关系,我让用户与上面的每个表(User-Food,User-Cocktails,User-Sweets)或我喜欢的桌子有关系。上面提到的所有表的外键。
后者不是我猜的最佳解决方案。
答案 0 :(得分:2)
您基本上有两个选择:
create table favorites (
favoritesId int auto_increment primary key,
userId,
which varchar(255),
id int,
foreign key (userId) references users(userId)
);
这简洁,简洁,可让您添加新实体。
或者,您可以单独列出每个:
create table favorites (
favoritesId int auto_increment primary key,
foodId int,
cocktailsId int,
. . .
foreign key (userId) references users(userId),
foreign key (foodId) references foods(foodId),
foreign key (cocktailsId) references cocktails(cocktailsId),
. . .
);
这不太简洁,但它允许您添加显式外键引用。如果需要的话,它还可以很容易地在一行中表示多个收藏夹。
答案 1 :(得分:1)
您可以创建一个Favorite
表
并从另外四个表中添加FOREIGN KEY
看起来像:
CREATE TABLE User (`ID` int not null, `Name` varchar(5)) ;
INSERT INTO User (`ID`, `Name`)
VALUES (1, 'Jogn'), (2, 'Henry') ;
CREATE TABLE Food (`ID` int, `calories` int) ;
INSERT INTO Food (`ID`, `calories`)
VALUES (1, 123), (2, 456) ;
CREATE TABLE Cocktails (`ID` int, `Alcoholic` int) ;
INSERT INTO Cocktails (`ID`, `Alcoholic`)
VALUES (1, 30), (2, 40) ;
CREATE TABLE Sweets (`ID` int, `Name` varchar(5)) ;
INSERT INTO Sweets (`ID`, `Name`)
VALUES (1, 'candy'), (2, 'cake') ;
CREATE TABLE Favorite
(`ID` int
, `UserID` int not null
, `FoodID` int
, `CocktailsID` int
, `SweetsID` int
)
;
ALTER TABLE `User` ADD CONSTRAINT PK_User PRIMARY KEY (`ID`);
ALTER TABLE `Food` ADD CONSTRAINT PK_Food PRIMARY KEY (`ID`);
ALTER TABLE `Cocktails` ADD CONSTRAINT PK_Cocktails PRIMARY KEY (`ID`);
ALTER TABLE `Sweets` ADD CONSTRAINT PK_Sweets PRIMARY KEY (`ID`);
ALTER TABLE `Favorite` ADD CONSTRAINT FK_Favorite_User
FOREIGN KEY (`UserID`) REFERENCES `User`(`ID`);
ALTER TABLE `Favorite` ADD CONSTRAINT FK_Favorite_Food
FOREIGN KEY (`FoodID`) REFERENCES `Food`(`ID`);
ALTER TABLE `Favorite` ADD CONSTRAINT FK_Favorite_Cocktails
FOREIGN KEY (`CocktailsID`) REFERENCES `Cocktails`(`ID`);
ALTER TABLE `Favorite` ADD CONSTRAINT FK_Sweetss
FOREIGN KEY (`SweetsID`) REFERENCES `Sweets`(`ID`);
INSERT INTO Favorite
(`ID`, `UserID`, `FoodID`, `CocktailsID`, `SweetsID`)
VALUES
(1, 1, '1', NULL, NULL),
(2, 2, NULL, '2', NULL),
(3, 1, NULL, NULL, '1')
;
当我插入不存在的糖果值
时INSERT INTO Favorite
(`ID`, `UserID`, `FoodID`, `CocktailsID`, `SweetsID`)
VALUES
(3, 1, NULL, NULL, 4)
;
它会抛出异常
Cannot add or update a child row: a foreign key constraint fails (`db_9_1a5d3f`.`favorite`, CONSTRAINT `FK_Sweetss` FOREIGN KEY (`SweetsID`) REFERENCES `sweets` (`ID`))
你可以通过这个SQL脚本查询它们(也许创建一个视图):
select
T1.ID FavoriteID,
T1.`UserID`,
case when T2.ID is not null then 'Food'
when T3.ID is not null then 'Cocktails'
when T4.ID is not null then 'Sweets'
end type,
COALESCE(T2.ID,T3.ID,T4.ID) ID
from Favorite T1
left join Food T2 on T1.`FoodID` = T2.`ID`
left join Cocktails T3 on T1.`CocktailsID` = T3.`ID`
left join Sweets T4 on T1.`SweetsID` = T4.`ID`
| FavoriteID | UserID | type | ID |
|------------|--------|-----------|----|
| 1 | 1 | Food | 1 |
| 2 | 2 | Cocktails | 2 |
| 3 | 1 | Sweets | 1 |
如果您想要测试:SQL Fiddle Test Demo Link
答案 2 :(得分:0)
为所有项目类型创建一个包含单列的favorite
表。
CREATE TABLE favorite
(user integer,
item integer,
item_type varchar(256),
PRIMARY KEY (user,
item,
item_type),
FOREIGN KEY (user)
REFERENCES user
(id));
item
是相应表格中的ID(food
,cocktail
或sweet
)。
item_type
来确保唯一性,因为item
对于两个不同类型的项目可以是相同的。它是例如表名('food'
,'cocktail'
或'sweet'
)。它还可以充当辅助列,以指定项item
指向的类型。
优点:
缺点:
item
上添加外键约束,因为它每行引用不同的表。您必须实施触发器以确保参照完整性。创建一个favorite
表,其中包含每个项类型的列。
CREATE TABLE favorite
(id integer
AUTO_INCREMENT,
user integer,
food integer,
cocktail integer,
sweet integer,
PRIMARY KEY (id),
FOREIGN KEY (food)
REFERENCES food
(id),
FOREIGN KEY (cocktail)
REFERENCES cocktail
(id),
FOREIGN KEY (sweet)
REFERENCES sweet
(id),
UNIQUE (user,
food),
UNIQUE (user,
cocktail),
UNIQUE (user,
sweet));
优点:
缺点:
NULL
行。这需要在应用程序中使用额外的逻辑,或者必须封装在触发器或过程中。如果用户每个项目类型只能有一个收藏夹,那么可能是个不错的选择。
引入一个公共item
表,让不同的项表引用该公用表。收藏夹表格仅引用公用表格。
CREATE TABLE item
(id integer
AUTO_INCREMENT,
PRIMARY KEY (id));
INSERT INTO item
SELECT NULL
FROM food
UNION ALL
SELECT NULL
FROM cocktail
UNION ALL
SELECT NULL
FROM sweet;
ALTER TABLE food
ADD (item integer,
FOREIGN KEY (item)
REFERENCES item
(id));
ALTER TABLE cocktail
ADD (item integer,
FOREIGN KEY (item)
REFERENCES item
(id));
ALTER TABLE sweet
ADD (item integer,
FOREIGN KEY (item)
REFERENCES item
(id));
UPDATE food
SET item = (SELECT count(*)
FROM food s
WHERE s.id <= food.id);
UPDATE cocktail
SET item = (SELECT count(*)
FROM cocktail s
WHERE s.id <= food.id)
+ (SELECT count(*)
FROM food);
UPDATE sweet
SET item = (SELECT count(*)
FROM sweet s
WHERE s.id <= food.id)
+ (SELECT count(*)
FROM food)
+ (SELECT count(*)
FROM cocktail);
ALTER TABLE food
MODIFY item integer
NOT NULL;
ALTER TABLE cocktail
MODIFY item integer
NOT NULL;
ALTER TABLE sweet
MODIFY item integer
NOT NULL;
CREATE TABLE favorite
(user integer,
item integer,
PRIMARY KEY (user,
item),
FOREIGN KEY (user)
REFERENCES user
(id),
FOREIGN KEY (item)
REFERENCES item
(id));
您可以选择在item
中添加帮助列,以指定项目类型id
。您也可以选择从不同的商品表(id
,food
或cocktail
)中删除sweet
,然后使用item
作为主键。
优点:
缺点:
item
。也可以通过某种触发器来处理 - 实际上它只需要创建一个新的item.id
来满足相应项目表中的外键约束(food
,cocktail
或sweet
),所以它相当简单。