使用组合创建表 PRIMARY KEY 或使用 UNIQUE INDEX 对于两列,保证 col1、col2 的唯一性。是否有一种棘手的方法可以使两列的相反顺序也唯一(col2,col1)?

例如

PRIMARY KEY (col1, col2)

或者

UNIQUE INDEX (col1, col2)

如果我们有 col1=33 && col2=54;我们怎样才能避免 INSERTcol1=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在修改或查询表时较高的值。

许可以下: CC-BY-SA归因
不隶属于 dba.stackexchange
scroll top