我表达了记录和搜索标签之间的关系,可以附加到这样的记录:
TABLE RECORDS
id
name
TABLE SEARCHTAGS
id
recordid
name
我希望能够根据他们拥有的搜索标签来选择记录。例如,我希望能够选择所有具有searchtags的记录:
(1 OR 2 OR 5) AND (6 OR 7) AND (10)
使用上面的数据结构,我不确定如何构造SQL来实现这一目标。
有什么建议吗?
谢谢!
答案 0 :(得分:2)
您可能需要尝试以下操作:
SELECT r.id, r.name
FROM records r
WHERE EXISTS (SELECT NULL FROM searchtags WHERE recordid = r.id AND id IN (1, 2, 5)) AND
EXISTS (SELECT NULL FROM searchtags WHERE recordid = r.id AND id IN (6, 7)) AND
EXISTS (SELECT NULL FROM searchtags WHERE recordid = r.id AND id IN (10));
测试用例:请注意,只有记录1和4才符合查询条件。
CREATE TABLE records (id int, name varchar(10));
CREATE TABLE searchtags (id int, recordid int);
INSERT INTO records VALUES (1, 'a');
INSERT INTO records VALUES (2, 'b');
INSERT INTO records VALUES (3, 'c');
INSERT INTO records VALUES (4, 'd');
INSERT INTO searchtags VALUES (1, 1);
INSERT INTO searchtags VALUES (2, 1);
INSERT INTO searchtags VALUES (6, 1);
INSERT INTO searchtags VALUES (10, 1);
INSERT INTO searchtags VALUES (1, 2);
INSERT INTO searchtags VALUES (2, 2);
INSERT INTO searchtags VALUES (3, 2);
INSERT INTO searchtags VALUES (1, 3);
INSERT INTO searchtags VALUES (10, 3);
INSERT INTO searchtags VALUES (5, 4);
INSERT INTO searchtags VALUES (7, 4);
INSERT INTO searchtags VALUES (10, 4);
结果:
+------+------+
| id | name |
+------+------+
| 1 | a |
| 4 | d |
+------+------+
2 rows in set (0.01 sec)
答案 1 :(得分:1)
SELECT
id, name
FROM
records
WHERE
EXISTS (
SELECT 1 FROM searchtags WHERE recordid = records.id AND id IN (1, 2, 5)
)
AND EXISTS (
SELECT 1 FROM searchtags WHERE recordid = records.id AND id IN (6, 7)
)
AND EXISTS (
SELECT 1 FROM searchtags WHERE recordid = records.id AND id IN (10)
)
答案 2 :(得分:0)
不确定如何在mysql中执行此操作,但在t-sql中,您可以执行以下操作:
SELECT id, name FROM RECORDS where id in (SELECT recordid from SEARCHTAGS where id in (1,2,5,6,7,10))
我可能完全不理解你的问题......但我尽了最大努力。
答案 3 :(得分:0)
尝试:
SELECT R.*
FROM RECORDS R, SEARCHTAGS S
WHERE R.id == S.recordid
AND S.name in (1,2,5,6,7,10);
不知道你是否需要S.name或S.id,但这只是一个例子。
答案 4 :(得分:0)
select RECORDS.name
from RECORDS join SEARCHTAGS
on RECORDS.id = SEARCHTAGS.recordid
where RECORDS.id in (1,2,...)
答案 5 :(得分:0)
我第一次误读了这个问题,并认为这是在要求
(1 AND 2 AND 5) OR (6 AND 7) OR (10)
而不是正确的
(1 OR 2 OR 5) AND (6 OR 7) AND (10)
到目前为止,所有答案都集中在回答具体的例子,而不是解决更一般的问题“并假设下次我想要一套不同的标准”。
对于实际问题(查询1 ),我的选择答案不能做得更好:
SELECT r.id, r.name
FROM Records AS r
WHERE EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (1, 2, 5))
AND EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (6, 7))
AND EXISTS(SELECT * FROM SearchTags AS s
WHERE r.id = s.recordid AND s.id IN (10));
这可以写成一个连接到SearchTags表的3个别名。
有几种方法可以回答替代方案 - 我认为这是最接近整洁和可扩展的方法。显然,一个项目(10)很容易(查询2 ):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (10) -- or '= 10' but IN is consistent with what follows
可以使用(查询3 )完成两项(6或7):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (6, 7)
GROUP BY r.id, r.name
HAVING COUNT(*) = 2
可以使用(查询4 )完成三项(1,2,5):
SELECT r.id, r.name
FROM records AS r JOIN searchtags AS t ON r.id = t.recordid
WHERE t.id IN (1, 2, 5)
GROUP BY r.id, r.name
HAVING COUNT(*) = 3
整个系列可以是三个术语的联盟。
此解决方案的缺点是必须为每组项目手动制作SQL。 如果要自动化“SQL生成”,则需要在表格中使用控制数据 - 有趣的搜索标记集:
CREATE TABLE InterestingTags(GroupID INTEGER, TagID INTEGER);
INSERT INTO InterestingTags(1, 1);
INSERT INTO InterestingTags(1, 2);
INSERT INTO InterestingTags(1, 5);
INSERT INTO InterestingTags(2, 6);
INSERT INTO InterestingTags(2, 7);
INSERT INTO InterestingTags(3, 10);
对于询问'(1 OR 2 OR 5)AND(...)'(合取正常形式)的查询,您可以写(查询5 ):
SELECT r.id, r.name
FROM records AS r JOIN
searchtags AS s ON r.id = s.recordID JOIN
interestingtags AS t ON s.id = t.tagID
GROUP BY r.id, r.name
HAVING COUNT(DISTINCT t.GroupID) = (SELECT COUNT(DISTINCT GroupID)
FROM InterestingTags);
这将检查给定记录的不同“有趣的标签组”的数量是否等于“有趣的标签组”的总数。
对于询问'(1 AND 2 AND 5)OR(...)'(析取范式)的查询,您可以使用InterestingTags编写连接并检查记录是否包含与标记组一样多的条目(查询6 ):
SELECT i.id, i.name
FROM (SELECT q.id, q.name, c.GroupSize,
COUNT(DISTINCT t.GroupID) AS GroupCount
FROM records AS q JOIN
searchtags AS s ON q.id = s.recordID JOIN
interestingtags AS t ON s.id = t.tagID JOIN
(SELECT GroupID, COUNT(*) AS GroupSize
FROM InterestingTags
GROUP BY GroupID) AS c ON c.GroupID = t.GroupID
GROUP BY q.id, q.name, c.GroupSize
) AS i
WHERE i.GroupCount = i.GroupSize;
我从Daniel Vassalo的回答中获取了测试数据,并用一些额外的值来增加它:
CREATE TABLE records (id int, name varchar(10));
CREATE TABLE searchtags (id int, recordid int);
INSERT INTO records VALUES (1, 'a');
INSERT INTO records VALUES (2, 'b');
INSERT INTO records VALUES (3, 'c');
INSERT INTO records VALUES (4, 'd');
INSERT INTO records VALUES (11, 'A11');
INSERT INTO records VALUES (21, 'B12');
INSERT INTO records VALUES (31, 'C13');
INSERT INTO records VALUES (41, 'D14');
INSERT INTO records VALUES (51, 'E15');
INSERT INTO records VALUES (61, 'F16');
INSERT INTO searchtags VALUES (1, 1);
INSERT INTO searchtags VALUES (2, 1);
INSERT INTO searchtags VALUES (6, 1);
INSERT INTO searchtags VALUES (10, 1);
INSERT INTO searchtags VALUES (1, 2);
INSERT INTO searchtags VALUES (2, 2);
INSERT INTO searchtags VALUES (3, 2);
INSERT INTO searchtags VALUES (1, 3);
INSERT INTO searchtags VALUES (10, 3);
INSERT INTO searchtags VALUES (5, 4);
INSERT INTO searchtags VALUES (7, 4);
INSERT INTO searchtags VALUES (10, 4);
INSERT INTO searchtags VALUES (1, 11);
INSERT INTO searchtags VALUES (2, 11);
INSERT INTO searchtags VALUES (5, 11);
INSERT INTO searchtags VALUES (6, 21);
INSERT INTO searchtags VALUES (7, 21);
INSERT INTO searchtags VALUES (10, 31);
INSERT INTO searchtags VALUES (1, 41);
INSERT INTO searchtags VALUES (6, 41);
INSERT INTO searchtags VALUES (10, 41);
INSERT INTO searchtags VALUES (2, 51);
INSERT INTO searchtags VALUES (5, 51);
INSERT INTO searchtags VALUES (10, 51);
INSERT INTO searchtags VALUES (7, 61);
INSERT INTO searchtags VALUES (2, 61);
INSERT INTO searchtags VALUES (1, 61);
CREATE TABLE InterestingTags(GroupID INTEGER, TagID INTEGER);
INSERT INTO InterestingTags VALUES(1, 1);
INSERT INTO InterestingTags VALUES(1, 2);
INSERT INTO InterestingTags VALUES(1, 5);
INSERT INTO InterestingTags VALUES(2, 6);
INSERT INTO InterestingTags VALUES(2, 7);
INSERT INTO InterestingTags VALUES(3, 10);
我得到的输出是:
查询1
1 a
4 d
41 D14
查询2
1 a
3 c
4 d
31 C13
41 D14
51 E15
查询3
21 B12
查询4
11 A11
查询5
1 a
41 D14
4 d
查询6
4 d
31 C13
3 c
1 a
41 D14
51 E15
显然,如果我想按特定顺序输出,我会在查询中添加一个ORDER BY子句。