强制复合主键的顺序

时间:2011-12-06 12:56:25

标签: mysql

说我有下表

item_a_id, item_b_id, value

其中item_a_id和item_b_id是复合主键。在我的例子中,a,b和b,a是等价的。因此,我想确保item_a_id< item_b_id。显然,应用程序逻辑会强制执行此操作,但有没有办法确保数据库也这样做?

2 个答案:

答案 0 :(得分:3)

在相当当前版本的MySql中,您可以使用触发器emulate a check constraint来产生所需的行为。

答案 1 :(得分:2)

嗯,在您的情况下,您可以使用触发器在插入/更新之前检查值并交换它以确保item_a_id始终小于item_b_id

假设表名为item_links,您可以尝试:

DELIMITER |

CREATE TRIGGER ensure_a_b_before_insert BEFORE INSERT ON item_links
  FOR EACH ROW 
  BEGIN
    IF NEW.item_a_id > NEW.item_b_id THEN
      SET @tmp = NEW.item_b_id;
      SET NEW.item_b_id = NEW.item_a_id;
      SET NEW.item_a_id = @tmp;
    END IF;
  END;
|

CREATE TRIGGER ensure_a_b_before_update BEFORE UPDATE ON item_links
  FOR EACH ROW 
  BEGIN
    IF NEW.item_a_id > NEW.item_b_id THEN
      SET @tmp = NEW.item_b_id;
      SET NEW.item_b_id = NEW.item_a_id;
      SET NEW.item_a_id = @tmp;
    END IF;
  END;
|

DELIMITER ;

这是我测试插入时得到的结果:

mysql> INSERT INTO  `item_links` (`item_a_id`, `item_b_id`, `value`)
    -> VALUES ('1',  '2',  'a')
    ->      , ('3',  '2',  'b')
    ->      , ('4',  '1',  'c');
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM `item_links`;
+-----------+-----------+-------+
| item_a_id | item_b_id | value |
+-----------+-----------+-------+
|         1 |         2 | a     |
|         2 |         3 | b     |
|         1 |         4 | c     |
+-----------+-----------+-------+
3 rows in set (0.00 sec)

更新也有效:

mysql> UPDATE `item_links` 
    -> SET `item_a_id` = 100, `item_b_id` = 20 
    -> WHERE `item_a_id` = 1 AND `item_b_id` = 2;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM `item_links`;
+-----------+-----------+-------+
| item_a_id | item_b_id | value |
+-----------+-----------+-------+
|        20 |       100 | a     |
|         2 |         3 | b     |
|         1 |         4 | c     |
+-----------+-----------+-------+
3 rows in set (0.00 sec)