-
16-10-2019 - |
题
使用组合创建表 PRIMARY KEY
或使用 UNIQUE INDEX
对于两列,保证 col1、col2 的唯一性。是否有一种棘手的方法可以使两列的相反顺序也唯一(col2,col1)?
例如
PRIMARY KEY (col1, col2)
或者
UNIQUE INDEX (col1, col2)
如果我们有 col1=33 && col2=54
;我们怎样才能避免 INSERT
的 col1=54 && col2=33
?
解决方案
您可能想尝试创建一个触发器来检查 (col1,col2) 是否存在为 (col2,col1)
这是一个例子:
use test
drop table if exists ali;
create table ali
(
col1 int not null,
col2 int not null,
primary key (col1,col2)
);
DELIMITER $$
CREATE TRIGGER ali_bi BEFORE INSERT ON ali FOR EACH ROW
BEGIN
DECLARE found_count,newcol1,newcol2,dummy INT;
SET newcol1 = NEW.col1;
SET newcol2 = NEW.col2;
SELECT COUNT(1) INTO found_count FROM ali
WHERE col1 = newcol2 AND col2 = newcol1;
IF found_count = 1 THEN
SELECT 1 INTO dummy FROM information_schema.tables;
END IF;
END; $$
DELIMITER ;
INSERT INTO ali VALUES (1,2);
INSERT INTO ali VALUES (3,4);
INSERT INTO ali VALUES (2,1);
INSERT INTO ali VALUES (4,3);
SELECT * FROM ali;
该触发器设计为在 FOUND_COUNT 为 1 时故意中断。
这是执行的示例:
mysql> use test
Database changed
mysql> drop table if exists ali;
Query OK, 0 rows affected (0.03 sec)
mysql> create table ali
-> (
-> col1 int not null,
-> col2 int not null,
-> primary key (col1,col2)
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> DELIMITER $$
mysql> CREATE TRIGGER ali_bi BEFORE INSERT ON ali FOR EACH ROW
-> BEGIN
-> DECLARE found_count,newcol1,newcol2,dummy INT;
-> SET newcol1 = NEW.col1;
-> SET newcol2 = NEW.col2;
-> SELECT COUNT(1) INTO found_count FROM ali
-> WHERE col1 = newcol2 AND col2 = newcol1;
-> IF found_count = 1 THEN
-> SELECT 1 INTO dummy FROM information_schema.tables;
-> END IF;
-> END; $$
Query OK, 0 rows affected (0.07 sec)
mysql> DELIMITER ;
mysql> INSERT INTO ali VALUES (1,2);
Query OK, 1 row affected (0.07 sec)
mysql> INSERT INTO ali VALUES (3,4);
Query OK, 1 row affected (0.06 sec)
mysql> INSERT INTO ali VALUES (2,1);
ERROR 1172 (42000): Result consisted of more than one row
mysql> INSERT INTO ali VALUES (4,3);
ERROR 1172 (42000): Result consisted of more than one row
mysql> SELECT * FROM ali;
+------+------+
| col1 | col2 |
+------+------+
| 1 | 2 |
| 3 | 4 |
+------+------+
2 rows in set (0.00 sec)
mysql>
试一试 !!!
注意这不适用于批量插入。仅当一次插入一行时。
我已经使用了这种技术,并在其他 DBA StackExchange 问题中建议了它
更新 2012-02-29 11:46 美国东部时间
我尝试再次插入相同的四行。
INSERT INTO ali VALUES (1,2);
INSERT INTO ali VALUES (3,4);
INSERT INTO ali VALUES (2,1);
INSERT INTO ali VALUES (4,3);
SELECT * FROM ali;
这是我得到的
mysql> INSERT INTO ali VALUES (1,2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 'PRIMARY'
mysql> INSERT INTO ali VALUES (3,4);
ERROR 1062 (23000): Duplicate entry '3-4' for key 'PRIMARY'
mysql> INSERT INTO ali VALUES (2,1);
ERROR 1172 (42000): Result consisted of more than one row
mysql> INSERT INTO ali VALUES (4,3);
ERROR 1172 (42000): Result consisted of more than one row
mysql> SELECT * FROM ali;
+------+------+
| col1 | col2 |
+------+------+
| 1 | 2 |
| 3 | 4 |
+------+------+
2 rows in set (0.00 sec)
mysql>
尽管消息很奇怪,但这种触发方法效果很好。
其他提示
在标准的SQL DBMS中,您可以通过订购ID号并使用检查约束来强制执行这种要求。应用程序代码,存储过程或用户定义的功能负责将ID号以正确的顺序发布。
create table friends (
user_a integer not null, -- references users, not shown
user_b integer not null, -- references users, not shown
primary key (user_a, user_b),
check (user_a < user_b)
);
但是MySQL不会强制执行检查约束。使用MySQL,我仍然使用存储过程(不是应用程序代码)将ID号放入正确的顺序。但是,我还会不时地运行查询或报告,以确保用户_a的所有值小于user_b的值。
select *
from friends
where user_a >= user_b;
我可能不包括更新语句以最初修复这些值。我想跟踪我的存储过程中的哪些过程,应用程序或用户直接将数据插入表中。 (您可以撤销直接访问表,并需要所有访问权限才能通过存储过程。但是,在某些旧系统中,这不是实用的;太多的代码无法重写。还有其他选择。)
不幸的是,某些要求必须作为管理程序,例如运行报告。
即使您使用反向索引,这些规则也不能由MySQL中的唯一索引强制执行。您需要在应用程序业务逻辑或使用数据库触发器/功能/过程中执行此规则,该数据库保存之前检查数据。
我知道这对游戏有点晚了,但是我可以补充...
我们也有类似的情况,除了ID1和ID2相同的情况外,它们实际上链接到同一表提供 有关的 再次,许多功能。
由于我们要查询在任一列中可能存在的潜在ID,因此两个索引实际上更合乎逻辑。...和权宜之计..........而且不太昂贵。
UNIQUE INDEX (col1, col2) + UNIQUE INDEX (col2, col1)
如果您使用的是整数/数字,请始终使COL1变为较低的值,而COL2在修改或查询表时较高的值。