在引用的 table 中找不到索引,其中引用的列显示为第一列

Cannot find an index in the referenced table where the referenced columns appear as the first columns

我在 mysql table 之后创建 link https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html

但是我一直收到这个错误

FOREIGN KEY (serial_no) REFERENCES tag_master(orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT:
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html for correct foreign key definition.

这里有 tables:

create table tag_master(
        orig_part_no VARCHAR(70) CHARACTER SET ascii NOT NULL,
        orig_serial_no VARCHAR(56) CHARACTER SET ascii NOT NULL,
        regist_part_no VARCHAR(70) CHARACTER SET ascii,
        regist_serilal_no VARCHAR(56) CHARACTER SET ascii,
        regist_comment VARCHAR(126) CHARACTER SET ascii,
        PRIMARY KEY (orig_part_no, orig_serial_no)
) ENGINE=INNODB;
create table reader_table(
        reader_id  VARCHAR(70) CHARACTER SET ascii NOT NULL,
        name VARCHAR(128) CHARACTER SET ascii,
        PRIMARY KEY (reader_id)
) ENGINE=INNODB;
create table tag_log(
        id BIGINT AUTO_INCREMENT,
        part_no VARCHAR(70) CHARACTER SET ascii NOT NULL,
        serial_no VARCHAR(56) CHARACTER SET ascii NOT NULL,
        access_date DATE,
        latitude FLOAT,
        longitude FLOAT,
        reader_id VARCHAR(70) CHARACTER SET ascii NOT NULL,
        current_part_no VARCHAR(105) CHARACTER SET ascii,
        current_serial_no VARCHAR(70) CHARACTER SET ascii,
        current_comment VARCHAR(128) CHARACTER SET ascii,
        PRIMARY KEY (id),

        INDEX (part_no, serial_no),
        INDEX (reader_id),

        FOREIGN KEY(part_no, serial_no) REFERENCES tag_master(orig_part_no, orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT,
        FOREIGN KEY(reader_id) REFERENCES reader_table(reader_id)

) ENGINE=INNODB;

part_noreader_id 的外键有效,但不知何故我无法创建外键 serial_noorig_serial_no。 我尝试了 ALTER TABLE tag_log ADD FOREIGN KEY (serial_no) REFERENCES tag_master(orig_serial_no) ON UPDATE CASCADE ON DELETE RESTRICT; 但它仍然不起作用,没有任何意义。

desc tag_log table 看起来像这样:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| id                | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| part_no           | varchar(70)  | NO   | MUL | NULL    |                |
| serial_no         | varchar(56)  | NO   |     | NULL    |                |
| access_date       | date         | YES  |     | NULL    |                |
| latitude          | float        | YES  |     | NULL    |                |
| longitude         | float        | YES  |     | NULL    |                |
| reader_id         | varchar(70)  | NO   | MUL | NULL    |                |
| current_part_no   | varchar(105) | YES  |     | NULL    |                |
| current_serial_no | varchar(70)  | YES  |     | NULL    |                |
| current_comment   | varchar(128) | YES  |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

OS: Ubuntu18.04

MySQL: mysql Ver 14.14 Distrib 5.7.29, for Linux (x86_64) using EditLine wrapper Server version: 5.7.29-0ubuntu0.18.04.1 (Ubuntu)

这个外键...

FOREIGN KEY (serial_no) 
    REFERENCES tag_master(orig_serial_no) 
    ON UPDATE CASCADE ON DELETE RESTRICT

... 需要 tag_master(orig_serial_no) 上的索引,或者至少是 orig_serial_no 首先出现的复合索引。在您当前的设置中情况并非如此,其中 tag_master 的主键是 (part_no, serial_no)(相关列出现在第二个位置,而不是第一个)。

解决此问题的一种方法是更改​​ tag_master 的主键中列的顺序:

PRIMARY KEY (orig_serial_no, orig_part_no)

这还需要您更改引用两列的 tag_log 中复合外键中列的顺序:

FOREIGN KEY(serial_no, part_no) 
    REFERENCES tag_master(orig_serial_no, orig_part_no) 
    ON UPDATE CASCADE ON DELETE RESTRICT

然后您可以创建额外的外键,如 this db fiddle 所示。

但是,话虽这么说,我只是不明白创建这个额外的外键的意义,因为你已经有了另一个覆盖它的键 (FOREIGN KEY(serial_no, part_no))。很可能,您只是不需要那个额外的约束,因为它提供的功能已经由复合键提供了。

好吧,我知道这个问题有点老,但我很难找到它,而且互联网上几乎没有任何东西可以帮助我。

我为解决我的问题所做的不是给 parent table(引用的 table)上的列一个主键,而是给它一个唯一键。然后在 child table(引用 table)上,我总是给出引用索引键的列。定义约束时,如果已经使用另一个约束来引用 parent child,则使用另一个约束。使用相同的约束可能不起作用,因为它对我不起作用。

这相当公平地解决了我的问题,我希望它对你也有用...