我有一个表,里面有一个名为ColumnName
该列的数据类型是JSON,
我正在努力让它成为unique key
,但这是不可能的,我收到了这条消息:
#3152 - JSON 列“columnName”不能在键规范中使用。
我想了解为什么我不能将该列设为唯一键。
请留下讨论此问题的官方文档。
谢谢。
问题更新于 2022 年 11 月 28 日:
我将解释为什么需要将 JSON 列标记为唯一键的实际用法。
在我的 Android 应用程序中,我使用 OTP(一次性密码),它有四种用途:
- 第一次使用,当用户想要登录他的帐户时:
有一个字段和一个按钮。用户将在字段中输入他的电子邮件,然后按按钮继续。
在 MySQL 中,我将检查用户表中是否存在电子邮件。如果电子邮件存在,我会将代码发送到他的电子邮件(4 位数字)并返回{"REQUEST_STATUS": 100}
给用户。不然我就回来{"REQUEST_STATUS": 740}
给用户。
在我的 Android 应用程序中,如果REQUEST_STATUS
was 100
,我会将用户导航到验证页面以继续该过程,但如果REQUEST_STATUS
was 740
,我会告诉用户输入的电子邮件不存在。
- 第二种用法,当用户想要创建一个新帐户时:
有两个字段和一个按钮。用户将在第一个字段中输入他的姓名,在第二个字段中输入他的电子邮件,然后按按钮继续。
在 MySQL 中,我将检查用户表中是否存在电子邮件。如果电子邮件不存在,我会将代码发送到他的电子邮件(4 位数字)并返回{"REQUEST_STATUS": 100}
给用户。不然我就回来{"REQUEST_STATUS": 813}
给用户。
在我的 Android 应用程序中,如果REQUEST_STATUS
was 100
,我会将用户导航到验证页面以继续该过程,但如果REQUEST_STATUS
was 813
,我会告诉用户输入的电子邮件已经存在。
- 第三种用法,当用户想要更改他的电子邮件时:
有一个字段和一个按钮。用户将在字段中输入新电子邮件,然后按按钮继续。
在 MySQL 中,我将检查用户表中是否存在电子邮件。如果该电子邮件不存在,我会将代码发送到他的新电子邮件(4 位数字)并返回{"REQUEST_STATUS": 100}
给用户。不然我就回来{"REQUEST_STATUS": 813}
给用户。
在我的 Android 应用程序中,如果REQUEST_STATUS
was 100
,我会将用户导航到验证页面以继续该过程,但如果REQUEST_STATUS
was 813
,我会告诉用户输入的新电子邮件已经存在。
- 第四种用法,当用户想要删除他的帐户时:
有一个名为“删除我的帐户”的按钮,用户将按该按钮继续。
我会将代码发送到他的电子邮件(4 位数字)并返回{"REQUEST_STATUS": 100}
给用户。
在我的 Android 应用程序中,如果REQUEST_STATUS
was 100
,我会将用户导航到验证页面以继续该过程。
所有发送到电子邮件的代码我都会将其存储在代码表中,该表如下所示:
CREATE TABLE CODES (
CODE CHAR(4) COLLATE UTF8_UNICODE_CI NOT NULL,
EMAIL CHAR(200) COLLATE UTF8_UNICODE_CI NOT NULL,
EXPIRATION_DATE DATETIME NOT NULL, -- Every code will be valid for 10 minutes only.
NAME CHAR(25) COLLATE UTF8_UNICODE_CI NULL,
NEW_EMAIL char(200) COLLATE UTF8_UNICODE_CI NULL,
REMAINING_ATTEMPTS TINYINT(4) NOT NULL, -- Every code has 5 attempts only.
TYPE TINYINT(4) NOT NULL
) ENGINE = INNODB DEFAULT CHARSET = UTF8 COLLATE = UTF8_UNICODE_CI;
ALTER TABLE CODES ADD UNIQUE KEY (EMAIL,TYPE);
类型列仅保存 1 到 4 之间的值。
如果用户想要登录,则类型列的值为1,2用于创建新帐户,3用于更改电子邮件,4用于删除帐户。
如果类型列的值为 1、3 或 4,则名称列将为空;如果类型列的值为 1、2 或 4,则 new_email 列将为空。
我不会说我喜欢这样设计表格,所以我将表格设计更改为:
CREATE TABLE CODES (
CODE CHAR(4) COLLATE UTF8_UNICODE_CI NOT NULL,
EMAIL CHAR(200) COLLATE UTF8_UNICODE_CI NOT NULL,
EXPIRATION_DATE DATETIME NOT NULL, -- Every code will be valid for 10 minutes only.
REMAINING_ATTEMPTS TINYINT(4) NOT NULL, -- Every code has 5 attempts only.
TYPE JSON NOT NULL -- It will look like this {"TYPE": 1} OR {"TYPE": 2, "NAME": "..."} OR {"TYPE": 3, "NEW_EMAIL": "..."} OR {"TYPE": 4}
) ENGINE = INNODB DEFAULT CHARSET = UTF8 COLLATE = UTF8_UNICODE_CI;
现在看起来好多了,但我无法将电子邮件和类型列设置为唯一键。
根据下面比尔·卡文的回答,我读到对生成的列进行索引以提供 JSON 列索引 https://dev.mysql.com/doc/refman/8.0/en/create-table-secondary-indexes.html#json-column-indirect-index,我明白了我该怎么做。
但这种方式的问题是我需要创建一个额外的列来从 JSON 内的字段中获取值。
是否可以使 JSON 中的电子邮件列和类型字段成为唯一键,而无需创建额外的列?