我有两张桌子battles
& battle_user
结构:
battles
表:
id create_date
1 2015/...
battle_user
表:
id battle_id user_id
1 1 1
2 1 2
每场战斗中只有2位用户接受,问题是:是否有办法使用primary/foreign keys
(或索引)来防止为同一2位用户插入另一场战斗?
防止这种情况:
battles
表:
id create_date
1 2015/...
2 2015/...
battle_user
表:
id battle_id user_id
1 1 1
2 1 2
3 2 1
4 2 2
防止在相同的2个用户之间创建2场战斗
答案 0 :(得分:1)
正如我在评论中所说,我不情愿地会展示如何以非规范化的方式使用一个独特的密钥,并且OP希望看到它。
这个概念是你知道用户,所以让他们楔入战斗表。然后你如何进入battle_users
表取决于你,我建议不要改变。
create table battlesA1
( id int auto_increment primary key,
createDt datetime not null,
user1 int not null,
user2 int not null,
-- FK Constraints go here (not shown, FK to users table)
-- Then unique constraint goes here
unique key(user1,user2) -- user1 is less than user2 on insert
-- so on insert, utilize the least() and greatest() functions (mysql)
-- or your front-end programming language
);
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00',1,2);
-- success
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00',1,2);
-- Error 1062, Duplicate Entry
least()
和greatest()
示例:
set @user1:=14;
set @user2:=7;
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00', least(@user1,@user2), greatest(@user1,@user2) );
-- success
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00', least(@user1,@user2), greatest(@user1,@user2) );
-- Error 1062, Duplicate Entry
set @user1:=6;
set @user2:=700;
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00', least(@user1,@user2), greatest(@user1,@user2) );
-- success
insert battlesA1(createDt,user1,user2) values ('2016-06-14 12:30:00', least(@user1,@user2), greatest(@user1,@user2) );
-- Error 1062, Duplicate Entry
drop table battlesA1; -- perhaps the best command you see here.
least(), greatest()和LAST_INSERT_ID()的手册页。后者没有使用,但在这种情况下经常使用。
所以你有它。你想看到它,我并不是非常自豪地展示它。
答案 1 :(得分:0)
条件并不简单,目前在MySQL表中插入行之前创建复杂检查的唯一方法是触发器。
我创建了一个触发器,用于检查这些用户是否有其他记录,但是存在问题(可能):您需要删除未创建的战斗ID。
.basrc
在空表中执行我得到:
delimiter $$
drop trigger if exists `battle_user_bi`$$
create trigger `battle_user_bi` before insert
on `battle_user` for each row
begin
declare msg varchar(100);
declare usersInBattle int default 0;
declare battleUsers int default 0;
declare otherUser int default 0;
set usersInBattle= (select count(*)
from `battle_user` bu
where bu.battle_id = new.battle_id);
if usersInBattle = 1 then
-- getting the other user
set otherUser = (select user_id
from `battle_user` bu
where bu.battle_id = new.battle_id);
-- getting the same users in other battles
set battleUsers =
(select count(*) from
(select bu.battle_id
from `battle_user` bu
where bu.battle_id <> new.battle_id
and bu.user_id = otherUser)
b1 inner join
(select bu.battle_id
from `battle_user` bu
where bu.battle_id <> new.battle_id
and bu.user_id = new.user_id) b2 on b1.battle_id = b2.battle_id);
if battleUsers > 0 then
set msg = "There is already one battle for this users... ";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
end if;
end if;
end$$
delimiter ;