在所有排列中确保FK唯一性的最佳方法是什么?

时间:2019-02-24 10:41:01

标签: mysql database database-design

我有一个constructor(props) { super(props); this.state = { loading: true, open: false }; } toggleDropDown = () => { this.setState({ open: !this.state.open }); }; <div className="content"> <div onClick={event => { event.stopPropagation(); }} onFocus={() => { this.toggleDropDown(); }} onBlur={() => { this.toggleDropDown(); }} tabIndex="0" className="ui right floated dropdown" > <i className="ellipsis vertical icon" /> {this.state.open ? ( <div className="menu"> <div className="item"> <i className="edit icon" /> Edit Post </div> <div className="item"> <i className="delete icon" />Remove Post </div> <div className="item"> <i className="hide icon" /> Hide Post </div> </div> ) : null} </div> <div className="header">{schedule.title}</div> <div className="description"> <p>{schedule.description}</p> </div> <div className="meta"> <span className="right floated time"> {moment(schedule.date).fromNow()} </span> </div> </div> 关系,它将两个用户的关系映射到一起。

这是两个FK:

  1. Friendship
  2. fk_friend_one_id

我有一个fk_friend_two_id的{​​{1}},但您可以用两种方式插入ID,但仍然可以使用:

UNIQUE INDEX

在这种情况下,我应该如何实施唯一性?

以下是我想到的一些解决方案:

  1. 只需始终按两个顺序插入。
  2. 确保(fk_friend_one_id, fk_friend_two_id)> INSERT INTO friendship (fk_friend_one_id, fk_friend_two_id) VALUES (1, 2); INSERT INTO friendship (fk_friend_one_id, fk_friend_two_id) VALUES (2, 1); 。遗憾的是,由于fk_friend_two_id不执行任何操作,因此无法在MySQL的数据库级别强制实施。

3 个答案:

答案 0 :(得分:1)

从MySql 8.0.16开始,您可以添加实际执行某些操作的CHECK constraint

(在MySql 5.7和8.0.16之间,您可以添加一个,但它只会被忽略)

对于MariaDb,自版本10.2.1起实施了有效的CHECK约束。 Reference

因此,如果您的版本支持它,则可能类似于以下示例:

    iter = len(string.split('/'))-1

    directory_path_str = ""
    for i in range(0,iter):
        directory_path_str = directory_path_str + srtr.split('/')[i] + "/"
create table Friend (
  id int primary key auto_increment, 
  name varchar(30) not null
);

insert into Friend (name) values
('John Doe'), ('Jane Shepard')

create table Friendship (
  id int primary key auto_increment,
  fk_friend_one_id int not null,
  fk_friend_two_id int not null,
  CONSTRAINT chk_friend2_gt_friend1 check (fk_friend_two_id > fk_friend_one_id),
  CONSTRAINT fk_friend_one_id foreign key (fk_friend_one_id) references Friend(id),
  CONSTRAINT fk_friend_two_id foreign key (fk_friend_two_id) references Friend(id),
  CONSTRAINT idx_friends unique index (fk_friend_one_id, fk_friend_two_id)
);
CONSTRAINT `chk_friend2_gt_friend1` failed for `mydb`.`Friendship`
insert into Friendship (fk_friend_one_id, fk_friend_two_id) value (2, 1);
CONSTRAINT `chk_friend2_gt_friend1` failed for `mydb`.`Friendship`
insert into Friendship (fk_friend_one_id, fk_friend_two_id) value (1, 1);
insert into Friendship (fk_friend_one_id, fk_friend_two_id) value (1, 2);
id | fk_friend_one_id | fk_friend_two_id
-: | ---------------: | ---------------:
 1 |                1 |                2

db <>提琴here

答案 1 :(得分:0)

可以使用stored procedurestriggers来实现。您可以尝试如下操作:

DELIMITER $

CREATE PROCEDURE `friendship_check`(IN fk_friend_one_id INT, IN fk_friend_two_id INT)
BEGIN
    IF fk_friend_one_id < fk_friend_two_id THEN
        SIGNAL SQLSTATE '45000'
           SET MESSAGE_TEXT = 'check constraint on friendship failed';
    END IF;
END$
DELIMITER ;


-- before insert trigger
DELIMITER $
CREATE TRIGGER `friendship_before_insert` BEFORE INSERT ON `Friendship`
FOR EACH ROW
BEGIN
    CALL friendship_check(new.fk_friend_one_id,new.fk_friend_two_id);
END$
DELIMITER ;

答案 2 :(得分:0)

(其他“答案”工作太辛苦。只需要一个UNIQUE和一些简单的SQL代码即可。)

如果您要在表中插入值$ x和$ y,请确保以规范的顺序放置它们:

INSERT INTO tbl (a, b)
    VALUES ( LEAST($x, $y),
             GREATEST($x, $y) )

UNIQUE(a, b)   -- or, better yet, PRIMARY KEY(a,b)

请注意,无论值是(1,2)还是(2,1),唯一要插入的行都是(1,2)

如果尝试将两者都放入,该怎么办?一个将以(1,2)的形式进入;另一个将在INSERT上出现错误。您可以通过INSERT IGNORE忽略该错误。如果还有其他列需要设置,请考虑使用INSERT .. ON DUPLICATE KEY UPDATE ..