Mysql SQL-多个左连接时返回重复标记

Mysql SQL-多个左连接时返回重复标记,mysql,sql,join,tags,left-join,Mysql,Sql,Join,Tags,Left Join,我正在获取一个带有多个链接标签和客户的预订 存在两个中间表来跟踪其他表之间的关联:tag\u assocs在bookings(本例中)和tags表之间,以及bookings和customers表之间的assocs SQL(简化): 现在,正在讨论的预订(a64l_ku-4af)只有一个标签-在DB中确认。也就是说,对于标签some标签,它在tag\u assocs中只有一个条目。事实上,这是通过一个唯一的索引阻止重复来实现的。但它会回来两次,也就是说 -------------------- |

我正在获取一个带有多个链接标签和客户的预订

存在两个中间表来跟踪其他表之间的关联:
tag\u assocs
bookings
(本例中)和
tags
表之间,以及
bookings
customers
表之间的
assocs

SQL(简化):

现在,正在讨论的预订(a64l_ku-4af)只有一个标签-在DB中确认。也就是说,对于标签
some标签
,它在
tag\u assocs
中只有一个条目。事实上,这是通过一个唯一的索引阻止重复来实现的。但它会回来两次,也就是说

--------------------
| tags             |
--------------------
| some-tag|some-tag|
--------------------
两部分问题:

1) 为什么会这样


2) 我可以通过将
GROUP\u CONCAT(tag…
更改为
GROUP\u CONCAT(DISTINCT tag…
来解决这个问题,但我觉得这是一个黑客行为,没有解决问题的原因。

让我们用一个例子来解释。假设我们有以下表格:

第1部分:原始查询

台账:

id | book
------------
 1 | Book 1
 2 | Book 2
表标记:

id | tag
-----------
 1 | Hobby
 2 | Sport
 3 | Work
表books2tags(用于使用适当的标签标记书籍):

现在,这两本书都附有两个标签,并且

SELECT b.book, t.tag FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
将是这样的(顺序无关):

要获得包含每本书的标签列表的字符串,我们使用

SELECT b.book, GROUP_CONCAT(t.tag SEPARATOR '|') as tags FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
GROUP BY b.book
结果可能是:

book   | tags
---------------------
book 1 | Hobby|Sport
book 2 | Work|Sport
第2部分:加入另一个表

如果我们有另一个带有可选附加信息的表,让我们举个例子:

id | book_id | example
-------------------------------------
 1 |      1  | 'example information'
 2 |      2  | 'another example'
我们通过左连接获得此附加信息:

SELECT b.book, t.tag, e.example FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
LEFT JOIN example e ON b.id = e.book_id
结果将是:

book   | tag     | example
----------------------------
book 1 | Hobby   | example information
book 1 | Hobby   | another example
book 1 | Sport   | example information
book 1 | Sport   | another example
book 2 | Sport   | NULL
book 2 | Work    | NULL
您可以看到,原始查询中book 1的每一行出现在结果中的频率与新联接表示例中的匹配行相同。如果我们使用旧查询按book获取标记,但使用添加的左联接,我们就可以通过

SELECT b.book, GROUP_CONCAT(t.tag SEPARATOR '|') as tags FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
LEFT JOIN example e ON b.id = e.book_id
GROUP BY b.book

book   | tags
---------------------
book 1 | Hobby|Hobby|Sport|Sport
book 2 | Work|Sport
这是因为现在有两行标记为“嗜好”和两行标记为“运动”。但要获得标记列表,我们使用DISTINCT获得正确的结果。这不是一种黑客行为:

SELECT b.book, GROUP_CONCAT(DISTINCT t.tag SEPARATOR '|') as tags FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
LEFT JOIN example e ON b.id = e.book_id
GROUP BY b.book

book   | tags
---------------------
book 1 | Hobby|Sport
book 2 | Work|Sport
结论

我想我已经演示了为什么标签可以通过加入另一个表来复制,作为对问题第1部分的回答,并且可以向您保证您的解决方案不是一个黑客,而是这个问题的正确解决方案


也看一看

看一看没有分组和没有分组的结果,你就会明白。而且:2)不是黑客。对于已经存在的行,每个产生多行的联接都会在结果集中产生同样多的行,并相应地乘以标记的出现次数。感谢您的澄清。@VMai-我假设2)是一个黑客,因为我假设MySQL句柄是不同的,首先获取所有行,然后删除重复项。如果是这样,这是我认为应该尽量避免的开销。是的,我能理解你的推理。我在这方面做了一些假设。正因为如此,我决定用一个可以理解的例子来解释它。哇,答案很好。谢谢你这么长时间来帮助我。这是最好的例子+1并接受。
book   | tag     | example
----------------------------
book 1 | Hobby   | example information
book 1 | Hobby   | another example
book 1 | Sport   | example information
book 1 | Sport   | another example
book 2 | Sport   | NULL
book 2 | Work    | NULL
SELECT b.book, GROUP_CONCAT(t.tag SEPARATOR '|') as tags FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
LEFT JOIN example e ON b.id = e.book_id
GROUP BY b.book

book   | tags
---------------------
book 1 | Hobby|Hobby|Sport|Sport
book 2 | Work|Sport
SELECT b.book, GROUP_CONCAT(DISTINCT t.tag SEPARATOR '|') as tags FROM books b
INNER JOIN books2tags bt ON b.id = bt.book_id
INNER JOIN tags t ON bt.tag_id = t.id
LEFT JOIN example e ON b.id = e.book_id
GROUP BY b.book

book   | tags
---------------------
book 1 | Hobby|Sport
book 2 | Work|Sport