当前位置: 首页 > 面试题库 >

SQL标记列表和标记过滤

柳晔
2023-03-14
问题内容

我有一个SQL数据库,用于存储用户和与用户相关联的标签(许多关系)。我有带有users表,tags表和“桥”表的经典架构,该表usertag将用户与标签链接在一起:

users table:
    +---------+---------+
    | Id      |  Name   |
    +---------+---------+
    | 1       | Alice   |
    | 2       | Bob     |
    | 3       | Carl    |
    | 4       | David   |
    | 5       | Eve     |
    +---------+---------+

tags table:
    +---------+---------+
    | Id      | Name    |
    +---------+---------+
    | 10      | Red     |
    | 20      | Green   |
    | 30      | Blue    |
    +---------+---------+

usertag table:
    +---------+---------+
    | UserId  |  TagId  |
    +---------+---------+
    | 2       | 10      |
    | 2       | 20      |
    | 1       | 30      |
    | 4       | 20      |
    | 4       | 10      |
    | 4       | 30      |
    | 5       | 10      |
    +---------+---------+

现在,我使用以下GROUP_CONCAT()函数进行查询以逗号分隔的字段的形式检索所有用户及其标签:

SELECT u.*, GROUP_CONCAT(ut.tagid) as tags FROM users as u LEFT JOIN usertag as ut ON u.id = ut.userid GROUP BY u.id

这给了我正确的输出:

output:
    +---------+---------+----------+
    | Id      |  Name   | Tags     |
    +---------+---------+----------+
    | 1       | Alice   | 30       |
    | 2       | Bob     | 10,20    |
    | 3       | Carl    | (null)   |
    | 4       | David   | 10,30,20 |
    | 5       | Eve     | 10       |
    +---------+---------+----------+

问题是,现在我想在此基础上实现标签过滤,即能够按标签(或多个标签)查询用户。过滤器应使用AND运算符工作。

例如:获得标记为红色(10)和绿色(20)的用户:

output:
    +---------+---------+----------+
    | Id      |  Name   | Tags     |
    +---------+---------+----------+
    | 2       | Bob     | 10,20    |
    | 4       | David   | 10,30,20 |
    +---------+---------+----------+

另一个示例:使用标签Red(10)获取用户:

output:
    +---------+---------+----------+
    | Id      |  Name   | Tags     |
    +---------+---------+----------+
    | 2       | Bob     | 10,20    |
    | 4       | David   | 10,30,20 |
    | 5       | Eve     | 10       |
    +---------+---------+----------+

另一个示例:使用标签为红色(10),绿色(20)和蓝色(30)的用户:

output:
    +---------+---------+----------+
    | Id      |  Name   | Tags     |
    +---------+---------+----------+
    | 4       | David   | 10,30,20 |
    +---------+---------+----------+

如何实现这样的查询?关于SO的这个问题非常相似,并且确实有效,但是它不涉及该GROUP_CONCAT()领域,我想保留原样。

这里的SQL提琴http://sqlfiddle.com/#!9/291a5c/8

编辑

可能有人认为此查询有效:

检索带有标签红色(10)和蓝色(20)的所有用户:

 SELECT u.name, GROUP_CONCAT(ut.tagid)
    FROM users as u
    JOIN usertag as ut ON u.id = ut.userid
   WHERE ut.tagid IN (10,20)
GROUP BY u.id
  HAVING COUNT(DISTINCT ut.tagid) = 2

这使:

output:
    +---------+---------+----------+
    | Id      |  Name   | Tags     |
    +---------+---------+----------+
    | 2       | Bob     | 10,20    |
    | 4       | David   | 10,20    |
    +---------+---------+----------+

哪个用户名明智(Bob和David)是正确的,但是该Tags字段缺少David列表中的标签30!


问题答案:

left jointags表,并在join子句中包含要搜索的ID,并在中检查计数having

SELECT u.id,u.name,GROUP_CONCAT(ut.tagid) as tags
FROM users u 
LEFT JOIN usertag as ut ON u.id = ut.userid 
LEFT JOIN tags t ON t.id=ut.tagid AND t.ID IN (10,20,30) --change this as needed
GROUP BY u.id,u.name
HAVING COUNT(ut.tagid) >= COUNT(t.id) AND COUNT(t.id) = 3 --change this number to the number of tags

FIND_IN_SET如果值有限,则可以使用另一种选择。例如,

SELECT * FROM (
SELECT u.*, GROUP_CONCAT(ut.tagid) as tags 
FROM users as u 
LEFT JOIN usertag as ut ON u.id = ut.userid 
GROUP BY u.id
) T
WHERE FIND_IN_SET('10',tags) > 0 AND FIND_IN_SET('20',tags) > 0


 类似资料:
  • 这是Web开发人员的完整参考指南,其中列出了与万维网联盟推荐的层叠样式表规范中定义的列表相关的所有CSS属性,级别2。 单击任何属性以查看其描述的示例 - Sr.No. 财产和描述 1 list-style 使用以下任何值定义与列表相关的样式 - list-style-image liststyle-position list-style-type 2 list-style-image 定义要用作

  • 我想创建一个符合JSON proto3的字符串,包括以下部分: 我不知道怎么做。这似乎是一个列表 我只尝试了“Newtonsoft Json. NET”,但这个问题对任何其他JSON库或自定义编码方法都是开放的。如何做到这一点? 编辑:这是一个序列化问题。我无法控制反序列化程序代码。

  • 我试图显示存储在mongodb数据库中的lat和lng的标记列表。我正在使用google-maps-react,这是我的子地图组件 我从这里的endpoint得到坐标 仍未显示

  • 您可以在当前光标处作一个标记,以便快速返回 m标记名称 定义标记。标记名称为一个字符 `标记名称 返回标记 mx 将当前光标处定义为标记 x `x 返回标记 x :marks 查看标记列表

  • 我有例外 有人能告诉我,我的配置中缺少了什么吗?

  • 使用合成标记和图层标记可存储注释和其他元数据,以及标记合成或图层中的重要时刻。合成标记显示在合成的时间标尺上,而每个图层标记显示在相应图层的持续时间条上。两种标记都可以保存相同的信息。 标记可以指单个时间点,也可以指一段持续时间。 After Effects 中的合成标记对应于 Adobe Premiere Pro 中的顺序标记。After Effects 中的图层标记对应于 Adobe Prem