为什么 JSON_TABLE() 加入不一致?
Why is JSON_TABLE() joining inconsistent?
在 MySQL 8 中,我们现在可以使用 JSON 类型的列,还可以使用 JSON_TABLE() 等内置函数,但有时我会在不同的场景中使用我看到了我没想到的结果。
Docs for JSON_TABLE() : https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html
也许JSON_TABLE不是用一块JSON完成拼接的方法。 MySQL 提供了一些搜索功能,但我没有想到可以替代 JSON_TABLE()
Docs for JSON search functions: https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html
架构 (MySQL v8.0)
CREATE TABLE USER (
NAME varchar(128) NOT NULL,
METADATA JSON NULL
);
INSERT INTO USER VALUES
('John', '[1,3]'),
('Jane', '[2]'),
('Bob', null),
('Sally', '[9]');
CREATE TABLE ROLES (
ID int NOT NULL,
NAME varchar(64) NOT NULL
);
INSERT INTO ROLES VALUES
(1, 'Originator'),
(2, 'Approver'),
(3, 'Reviewer');
查询 #1 - 为什么 Bob 没有 returned?
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
## Results ##
| NAME | METADATA | ID |
| ----- | -------- | --- |
| John | [1, 3] | 1 |
| John | [1, 3] | 3 |
| Jane | [2] | 2 |
| Sally | [9] | 9 |
查询 #2
SELECT * FROM ROLES;
## Results ##
| ID | NAME |
| --- | ---------- |
| 1 | Originator |
| 2 | Approver |
| 3 | Reviewer |
查询 #3 - 为什么没有结果?
SELECT *
FROM USER
JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
##There are no results to be displayed.
查询 #4 - 未加入 IN() return 的正确结果。
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
## Results ##
| NAME | METADATA | ID | ID | NAME |
| ---- | -------- | --- | --- | ---------- |
| John | [1, 3] | 1 | 1 | Originator |
| John | [1, 3] | 3 | 3 | Reviewer |
| Jane | [2] | 2 | 2 | Approver |
查询 #5 - Bob 在哪里?
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
LEFT JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
## Results ##
| NAME | METADATA | ID | ID | NAME |
| ----- | -------- | --- | --- | ---------- |
| John | [1, 3] | 1 | 1 | Originator |
| Jane | [2] | 2 | 2 | Approver |
| John | [1, 3] | 3 | 3 | Reviewer |
| Sally | [9] | 9 | | |
查询 #6 - 为什么 LEFT JOIN 与 IN() return 查询 #3 return 没有任何结果时的预期结果?
SELECT *
FROM USER
LEFT JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
## Results ##
| NAME | METADATA | ID | NAME |
| ----- | -------- | --- | ---------- |
| John | [1, 3] | 1 | Originator |
| John | [1, 3] | 3 | Reviewer |
| Jane | [2] | 2 | Approver |
| Bob | | | |
| Sally | [9] | | |
使用ISNULL
属性创建虚拟json
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
#1 No JOINS with JSON_TABLE where is Bob?
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
#2 Verify our ROLE recrods exist
SELECT * FROM ROLES;
#3 Regular JOIN with JSON_TABLE inside the IN(), why are there no results?
SELECT *
FROM USER
JOIN ROLES ON ROLES.id IN (
SELECT ID FROM USER, JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
#4 Regular JOIN with JSON_TABLE, returns expected results
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
#5 LEFT JOIN with JSON_TABLE, where is Bob?
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
LEFT JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
#6 LEFT JOIN with JSON_TABLE inside the IN(), returns expected results
SELECT *
FROM USER
LEFT JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
在 MySQL 8 中,我们现在可以使用 JSON 类型的列,还可以使用 JSON_TABLE() 等内置函数,但有时我会在不同的场景中使用我看到了我没想到的结果。
Docs for JSON_TABLE() : https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html
也许JSON_TABLE不是用一块JSON完成拼接的方法。 MySQL 提供了一些搜索功能,但我没有想到可以替代 JSON_TABLE()
Docs for JSON search functions: https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html
架构 (MySQL v8.0)
CREATE TABLE USER (
NAME varchar(128) NOT NULL,
METADATA JSON NULL
);
INSERT INTO USER VALUES
('John', '[1,3]'),
('Jane', '[2]'),
('Bob', null),
('Sally', '[9]');
CREATE TABLE ROLES (
ID int NOT NULL,
NAME varchar(64) NOT NULL
);
INSERT INTO ROLES VALUES
(1, 'Originator'),
(2, 'Approver'),
(3, 'Reviewer');
查询 #1 - 为什么 Bob 没有 returned?
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
## Results ##
| NAME | METADATA | ID |
| ----- | -------- | --- |
| John | [1, 3] | 1 |
| John | [1, 3] | 3 |
| Jane | [2] | 2 |
| Sally | [9] | 9 |
查询 #2
SELECT * FROM ROLES;
## Results ##
| ID | NAME |
| --- | ---------- |
| 1 | Originator |
| 2 | Approver |
| 3 | Reviewer |
查询 #3 - 为什么没有结果?
SELECT *
FROM USER
JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
##There are no results to be displayed.
查询 #4 - 未加入 IN() return 的正确结果。
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
## Results ##
| NAME | METADATA | ID | ID | NAME |
| ---- | -------- | --- | --- | ---------- |
| John | [1, 3] | 1 | 1 | Originator |
| John | [1, 3] | 3 | 3 | Reviewer |
| Jane | [2] | 2 | 2 | Approver |
查询 #5 - Bob 在哪里?
SELECT *
FROM USER,
JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
LEFT JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
## Results ##
| NAME | METADATA | ID | ID | NAME |
| ----- | -------- | --- | --- | ---------- |
| John | [1, 3] | 1 | 1 | Originator |
| Jane | [2] | 2 | 2 | Approver |
| John | [1, 3] | 3 | 3 | Reviewer |
| Sally | [9] | 9 | | |
查询 #6 - 为什么 LEFT JOIN 与 IN() return 查询 #3 return 没有任何结果时的预期结果?
SELECT *
FROM USER
LEFT JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
## Results ##
| NAME | METADATA | ID | NAME |
| ----- | -------- | --- | ---------- |
| John | [1, 3] | 1 | Originator |
| John | [1, 3] | 3 | Reviewer |
| Jane | [2] | 2 | Approver |
| Bob | | | |
| Sally | [9] | | |
使用ISNULL
属性创建虚拟json
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
#1 No JOINS with JSON_TABLE where is Bob?
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK;
#2 Verify our ROLE recrods exist
SELECT * FROM ROLES;
#3 Regular JOIN with JSON_TABLE inside the IN(), why are there no results?
SELECT *
FROM USER
JOIN ROLES ON ROLES.id IN (
SELECT ID FROM USER, JSON_TABLE(
USER.METADATA, "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);
#4 Regular JOIN with JSON_TABLE, returns expected results
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
#5 LEFT JOIN with JSON_TABLE, where is Bob?
SELECT *
FROM USER,
JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
LEFT JOIN ROLES ON ROLES.ID = JSON_ROLE_LINK.ID;
#6 LEFT JOIN with JSON_TABLE inside the IN(), returns expected results
SELECT *
FROM USER
LEFT JOIN ROLES ON ROLES.id IN (
SELECT ID FROM JSON_TABLE(
IFNULL(USER.METADATA,'[0]'), "$[*]"
COLUMNS(ID int PATH "$" NULL ON ERROR NULL ON EMPTY)
) AS JSON_ROLE_LINK
);