MySql 多对多搜索
MySql many to many search
我在处理多对多查找时遇到了一些问题。我有以下表格:
mysql> desc tags;
+------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| user_id | bigint(20) | NO | | NULL | |
| name | varchar(64) | NO | | NULL | |
+------------+------------------+------+-----+---------------------+----------------+
mysql> desc response_and_tag_relationships;
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| response_id | int(10) unsigned | NO | PRI | NULL | |
| tag_id | int(10) unsigned | NO | PRI | NULL | |
+-------------+------------------+------+-----+---------+-------+
mysql> desc survey_responses;
+--------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| survey_id | bigint(20) | NO | | NULL | |
| response | text | NO | | NULL | |
| score | smallint(6) | NO | | NULL | |
| recipient_id | bigint(20) | NO | | NULL | |
+--------------+------------------+------+-----+---------------------+----------------+
mysql> desc surveys;
+--------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| survey_token | varchar(255) | NO | | NULL | |
| type | smallint(6) | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
+--------------+------------------+------+-----+---------------------+----------------+
mysql> desc people;
+------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| email | varchar(255) | NO | | NULL | |
| last_sent | datetime | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
| dob | date | NO | | NULL | |
+------------+------------------+------+-----+---------------------+----------------+
我需要对响应中的标签进行分组。所以我想出了以下 SQL(以我有限的知识),它似乎可以完成这项工作:
SELECT
rat.tag_id,
rat.response_id,
t.name,
sr.response,
p.name,
p.email
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
WHERE
t.name IN (SELECT name FROM tags);
并产生以下结果:
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| tag_id | response_id | name | response | name | email |
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| 1 | 1 | ex | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 3 | 1 | repudiandae | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 4 | 1 | nam | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 5 | 1 | excepturi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 6 | 1 | quasi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 7 | 1 | perferendis | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 8 | 1 | nisi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 9 | 1 | sint | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
但我认为我的逻辑倒退了,因为这是响应驱动的,而不是标签驱动的(我认为...)。我基本上只需要在响应调用 api 方法中将结果与 return 相匹配的标签列表 - 那么有没有更好的方法来做到这一点?
编辑
我理想的结果是(虽然我不相信这是可能的):
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| tag_id | response_id | name | response | name | email |
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| 1,3,4,5,6,7,8,9 | 1 | ex | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
我还需要在 Laravel eloquent orm 中构建它,但我猜最好只使用原始查询
好的,从预期的结果来看,它更像是您在尝试对标签 ID 进行分组,是的,您可以使用 group_concat
函数作为
SELECT
group_concat(rat.tag_id) as tag_ids,
rat.response_id,
t.name,
sr.response,
p.name,
p.email
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
group by rat.response_id
现在上面针对每个不同 response_id
的查询会将 tag_id
分组为逗号分隔的字符串。
另请注意,当使用 group by
和 select 从多到多的数据时,可能 return 任何随机值,例如,如果我们将 t.name
保留在 selection 那么它可能是连接后的多对多关系中的任何一个,对于其他值也是如此。
理想情况下,您永远不应该 select 在这些情况下使用这些列或在 group_concat
之类的聚合函数中使用它们。理想的查询是
SELECT
group_concat(rat.tag_id) as tag_ids,
rat.response_id
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
group by rat.response_id
如果您还需要 select 中的其他列,那么如前所述,它可能是连接数据中的任何随机值。如果您想要全部,则对每个人使用 group_concat()
。
查看 group_concat
的手册,因为对于大型数据集,您可能需要增加 group_concat_max_len
我在处理多对多查找时遇到了一些问题。我有以下表格:
mysql> desc tags;
+------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| user_id | bigint(20) | NO | | NULL | |
| name | varchar(64) | NO | | NULL | |
+------------+------------------+------+-----+---------------------+----------------+
mysql> desc response_and_tag_relationships;
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| response_id | int(10) unsigned | NO | PRI | NULL | |
| tag_id | int(10) unsigned | NO | PRI | NULL | |
+-------------+------------------+------+-----+---------+-------+
mysql> desc survey_responses;
+--------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| survey_id | bigint(20) | NO | | NULL | |
| response | text | NO | | NULL | |
| score | smallint(6) | NO | | NULL | |
| recipient_id | bigint(20) | NO | | NULL | |
+--------------+------------------+------+-----+---------------------+----------------+
mysql> desc surveys;
+--------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| survey_token | varchar(255) | NO | | NULL | |
| type | smallint(6) | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
+--------------+------------------+------+-----+---------------------+----------------+
mysql> desc people;
+------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| email | varchar(255) | NO | | NULL | |
| last_sent | datetime | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
| dob | date | NO | | NULL | |
+------------+------------------+------+-----+---------------------+----------------+
我需要对响应中的标签进行分组。所以我想出了以下 SQL(以我有限的知识),它似乎可以完成这项工作:
SELECT
rat.tag_id,
rat.response_id,
t.name,
sr.response,
p.name,
p.email
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
WHERE
t.name IN (SELECT name FROM tags);
并产生以下结果:
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| tag_id | response_id | name | response | name | email |
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| 1 | 1 | ex | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 3 | 1 | repudiandae | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 4 | 1 | nam | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 5 | 1 | excepturi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 6 | 1 | quasi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 7 | 1 | perferendis | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 8 | 1 | nisi | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
| 9 | 1 | sint | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
但我认为我的逻辑倒退了,因为这是响应驱动的,而不是标签驱动的(我认为...)。我基本上只需要在响应调用 api 方法中将结果与 return 相匹配的标签列表 - 那么有没有更好的方法来做到这一点?
编辑
我理想的结果是(虽然我不相信这是可能的):
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| tag_id | response_id | name | response | name | email |
+--------+-------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------+-----------------------------------+
| 1,3,4,5,6,7,8,9 | 1 | ex | Repudiandae nam excepturi quasi perferendis nisi sint. Et excepturi id facere modi et sed. Eius nihil repellat veritatis voluptas. | Miss Sally Breitenberg | kkiehn@breitenberg.net |
我还需要在 Laravel eloquent orm 中构建它,但我猜最好只使用原始查询
好的,从预期的结果来看,它更像是您在尝试对标签 ID 进行分组,是的,您可以使用 group_concat
函数作为
SELECT
group_concat(rat.tag_id) as tag_ids,
rat.response_id,
t.name,
sr.response,
p.name,
p.email
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
group by rat.response_id
现在上面针对每个不同 response_id
的查询会将 tag_id
分组为逗号分隔的字符串。
另请注意,当使用 group by
和 select 从多到多的数据时,可能 return 任何随机值,例如,如果我们将 t.name
保留在 selection 那么它可能是连接后的多对多关系中的任何一个,对于其他值也是如此。
理想情况下,您永远不应该 select 在这些情况下使用这些列或在 group_concat
之类的聚合函数中使用它们。理想的查询是
SELECT
group_concat(rat.tag_id) as tag_ids,
rat.response_id
FROM
response_and_tag_relationships rat
INNER JOIN tags t ON t.id=rat.tag_id
INNER JOIN survey_responses sr ON sr.id=rat.response_id
INNER JOIN surveys s ON s.id = sr.survey_id
INNER JOIN people p ON p.id=sr.recipient_id
group by rat.response_id
如果您还需要 select 中的其他列,那么如前所述,它可能是连接数据中的任何随机值。如果您想要全部,则对每个人使用 group_concat()
。
查看 group_concat
的手册,因为对于大型数据集,您可能需要增加 group_concat_max_len