在MySQL

时间:2018-07-12 14:37:21

标签: mysql

目标是在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表进行额外的扫描,在性能方面是否有更好的解决方案?

1 个答案:

答案 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中始终至少有一个匹配项。

相关问题