目标是在MySQL v5.7中存储和查询JSON数组值。
给出两个表country(id,fullName)和country_synonyms(country_id,synonyms),并通过外键国家/地区ID具有一对多关系:
CREATE TABLE country(id INT, fullName VARCHAR(255));
CREATE TABLE country_synonyms(country_id INT,synonyms VARCHAR(255));
ALTER TABLE country ADD CONSTRAINT c_pk PRIMARY KEY(id);
ALTER TABLE country_synonyms ADD CONSTRAINT cs_pk PRIMARY KEY(country_id,synonyms);
ALTER TABLE country_synonyms ADD CONSTRAINT c_fk FOREIGN KEY (country_id) REFERENCES country(id) ON DELETE CASCADE;
INSERT INTO country(id,fullName) VALUES (1,'Afghanistan');
INSERT INTO country_synonyms(country_id,synonyms) VALUES (1,'afghanistan'),(1,'afg'),(1,'islamic republic of afghanistan');
将同义词列为数组可使用:
SELECT
T1.id,
T1.fullName,
cast(concat('[', group_concat(json_quote(T2.synonyms) ORDER BY synonyms SEPARATOR ','), ']') as json) AS synonyms
FROM country T1
LEFT JOIN country_synonyms T2
ON T1.id = T2.country_id
WHERE T1.id=1
GROUP BY country_id;
+----+-------------+-----------------------------------------------------------+
| id | fullName | synonyms |
+----+-------------+-----------------------------------------------------------+
| 1 | Afghanistan | ["afg", "afghanistan", "islamic republic of afghanistan"] |
+----+-------------+-----------------------------------------------------------+
按同义词搜索只会返回查询的值,如
SELECT
T1.id,
T1.fullName,
cast(concat('[', group_concat(json_quote(T2.synonyms) ORDER BY synonyms SEPARATOR ','), ']') as json) AS synonyms
FROM country T1
LEFT JOIN country_synonyms T2
ON T1.id = T2.country_id
WHERE T2.synonyms='afg'
GROUP BY country_id;`
+----+-------------+----------+
| id | fullName | synonyms |
+----+-------------+----------+
| 1 | Afghanistan | ["afg"] |
+----+-------------+----------+
如何“列出所有具有同义词'afg'的国家/地区同义词”?
编辑: 我发现此查询返回我想要的数组:
SELECT
T1.id,
T1.fullName,
cast(concat('[', group_concat(json_quote(T2.synonyms) ORDER BY synonyms SEPARATOR ','), ']') as json) AS synonyms
FROM country T1
LEFT JOIN country_synonyms T2
ON T1.id = T2.country_id
WHERE T1.id in (select country_id from country_synonyms where synonyms='afg')
GROUP BY country_id;
但是它正在对country_synonyms表进行额外的扫描,在性能方面是否有更好的解决方案?
答案 0 :(得分:0)
WHERE x IN (SELECT ...)
几乎总是可以变成JOIN
,这通常具有更好的性能。
要从选定的行中将值收集到JSON数组中,请使用JSON_ARRAYAGG()
而不是GROUP_CONCAT()
。
SELECT t1.id, t1.fullName, JSON_ARRAYAGG(t2.synonyms) AS synonyms
FROM country AS t1
JOIN country_synonyms AS t2 ON t1.id = t2.country_id
JOIN country_synonyms AS t2 ON t1.id = t3.country_id
WHERE t3.synonyms = 'afg'
GROUP BY t1.id
此外,您不需要使用LEFT JOIN
,因为条件表明country_synonyms
中始终至少有一个匹配项。