对不起,如果已经发布了,我看了一下,但真的不知道要搜索什么!
问题
我目前正在建立一个系统,用各种标签“标记”一个学生社团。我们的想法是,我们可以创建并应用所需的任何标签,然后使用API使用这些标签为不同的流程授权不同的社会(即检查是否已应用特定的标签)。
我们还使用这些标签来创建学生组。我希望用户能够设置标签过滤器(例如,他们应该能够说“我想组成一个由理学院的所有学术团体组成的小组”,在这些小组中,两个“学术”标签和“科学”标签。
我们的桌子的设计概述如下:
Societies Table:
+------------+-------------------+
| Society ID | Society Name |
+------------+-------------------+
| 1 | Physics Society |
| 2 | Chemistry Society |
+------------+-------------------+
Tags Table (Where the tags are defined):
+--------+--------------+
| Tag ID | Tag Name |
+--------+--------------+
| 1 | Academic |
| 2 | Science |
| 3 | Volunteering |
+--------+--------------+
Linking Table:
+---------+--------+----------+
| Link ID | Tag ID | Group ID |
+---------+--------+----------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 2 |
| 5 | 3 | 2 |
+---------+--------+----------+
在这种情况下,物理学会已被标记为“学术”和“科学”标签。
尝试解决方案
我现在需要一种搜索特定社会的方法。为了确保可以创建任何组,我认为我们需要包括运算符AND,OR和NOT以及方括号,然后从中构造一个SQL查询吗?如果有更好的方法,请纠正我!
用户将按以下格式输入过滤器(不一定是这种情况,但我想不出其他任何方法!):
({1,3} OR {6}) NOT {5}
使用PHP,然后将其转换为SQL查询:
WHERE (tag_id IN (1,3) OR tag_id IN (6)) AND tag_id NOT IN (5)
给出完整的查询
SELECT tag_links.society_id FROM tag_links WHERE (tag_id IN (1,3) OR tag_id IN (6)) AND tag_id NOT IN (5)
不幸的是,这行不通-结果多次返回相同的社会ID。我认为这是因为,由于每个社团有多行,因此查询不会排除任何带有tag_id 5标记的组。它不会返回将社团与tag_id 5链接的行。
有更好的方法吗?除了基本知识之外,我还没有丰富的SQL查询经验,因此可能遗漏了一些明显的东西...
非常感谢您的帮助!
托比
答案 0 :(得分:0)
我认为您想要一种找到具有特定标记集的社会的方法。如果是这样,那么这是应该起作用的常规查询:
SELECT
s.ID, s.Name
FROM Societies s
INNER JOIN Linking lnk
ON s.ID = lnk.Soc_ID
INNER JOIN Tags t
ON lnk.Tag_ID = t.ID
WHERE
t.Name IN ('Academic', 'Science')
GROUP BY
S.ID
HAVING COUNT(DISTINCT t.ID) = 2;
上面的查询将找到所有同时具有“学术”和“科学”标签的社会。根据您的样本数据,这只会找到物理学会。
要在下面发表您的评论,如果您要查找具有两个标签的社会,而又不具有一个或多个标签的社会,那么查询会变得有些丑陋,因为我们需要条件聚合:< / p>
SELECT
s.ID, s.Name
FROM Societies s
INNER JOIN Linking lnk
ON s.ID = lnk.Soc_ID
INNER JOIN Tags t
ON lnk.Tag_ID = t.ID
GROUP BY
S.ID
HAVING
SUM(CASE WHEN t.Name = 'Academic' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN t.Name = 'Science' THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN t.Name = 'Volunteering' THEN 1 ELSE 0 END) = 0;