gpt4 book ai didi

mysql - 多对多查询标记对象

转载 作者:行者123 更新时间:2023-11-29 00:36:46 24 4
gpt4 key购买 nike

我有这个数据库架构。为了简单起见,我将标记对象的东西称为对象:

用户

  • 用户编号
  • 登录

用户到对象表(多对多)

  • 用户编号
  • object_id

对象表

  • object_id
  • object_stuff

用 user_id 表标记对象(多对多,带额外列)

  • 用户编号
  • object_id
  • tag_id

标签表

  • tag_id
  • 标签名称

我一直在使用这样的查询来获取特定用户的对象以及对象的标签(如果用户标记了任何标签)。 如果您认为可以对此进行优化,请随时告诉我

@user_id = 'whatever user_id I want';
SELECT
o.object_id AS object_id,
o.object_stuff AS object_stuff,
IF (tags.tag_name IS NOT NULL, GROUP_CONCAT(tags.tag_name SEPARATOR '|'), 'N/A') AS tags
FROM object_table AS o
LEFT OUTER JOIN obj_to_users_table AS o2u ON o.object_id = o2u.object_id
LEFT OUTER JOIN users AS u ON u.user_id = o2u.user_id
LEFT OUTER JOIN obj_to_tag_users AS o2tu ON o.object_id = o2tu.object_id AND u.user_id = o2tu.user_id
LEFT OUTER JOIN tags AS t ON t.tag_id = o2t.tag_id
WHERE u.user_id = @user_id GROUP BY o.object_id

这会产生这样的结果:

object_id     object_stuff        tags
1 stuff1... tag1|tag2|tag3
2 stuff2... tag4|tag6|tag1
3 stuff3... tag7|tag2|tag5

我的问题是,例如,我想搜索标记为“tag2”的对象,我应该得到:

object_id     object_stuff        tags
1 stuff1... tag1|tag2|tag3
3 stuff3... tag4|tag2|tag1

但是相反,我丢失了对象附带的其他标签:

object_id     object_stuff        tags
1 stuff1... tag2
3 stuff3... tag2

如何修改我的 WHERE 子句,以便我可以获得标记为“tag2”的对象,同时在结果集中保留该对象具有的其他标记?

... WHERE u.user_id = @user_id AND t.tag_name LIKE '%tag2%' ...

最佳答案

首先,计算串联结果。

接下来,对这些串联的结果执行搜索以保留标签的分组:

SELECT * 
FROM
(
SELECT
o.object_id AS object_id,
o.object_stuff AS object_stuff,
IF (tags.tag_name IS NOT NULL,
GROUP_CONCAT(tags.tag_name SEPARATOR '|'), 'N/A') AS tags
FROM object_table AS o
LEFT OUTER JOIN obj_to_users_table AS o2u
ON o.object_id = o2u.object_id
LEFT OUTER JOIN users AS u
ON u.user_id = o2u.user_id
LEFT OUTER JOIN obj_to_tag_users AS o2tu
ON o.object_id = o2tu.object_id AND u.user_id = o2tu.user_id
LEFT OUTER JOIN tags AS t ON t.tag_id = o2t.tag_id
WHERE u.user_id = @user_id
GROUP BY o.object_id
) sub
WHERE sub.tags LIKE '%tag2%'

编辑:


这是一个使用 EXISTS 的示例.我还切换了 LEFT JOIN s 至 INNER JOIN s,因为搜索特定标签应该消除任何 objects没有tags无论如何。

虽然这个查询看起来更复杂,但它应该更有可能使用任何可用的索引。

我还提到使用一组额外的 INNER JOIN 执行相同类型的查询s,但是那个看起来会更复杂,因为您仍然必须使用子查询才能使用 DISTINCT摆脱额外的 JOIN 引入的任何可能的重复项s...所以我建议使用 EXISTS相反……

SELECT 
o.object_id AS object_id,
o.object_stuff AS object_stuff,
GROUP_CONCAT(t.tag_name SEPARATOR '|') AS tags
FROM object_table AS o
INNER JOIN obj_to_users_table AS o2u
ON o.object_id = o2u.object_id
INNER JOIN users AS u
ON u.user_id = o2u.user_id
INNER JOIN obj_to_tag_users AS o2tu
ON o.object_id = o2tu.object_id AND u.user_id = o2tu.user_id
INNER JOIN tags AS t
ON t.tag_id = o2t.tag_id
WHERE
u.user_id = @user_id
AND EXISTS (
SELECT 1
FROM tags AS targetTag
WHERE
targetTag.tag_id = o2t.tag_id
AND targetTag.tag_name = 'tag2'
)
GROUP BY o.object_id

关于mysql - 多对多查询标记对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13925711/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com