需要有关SELECT语句的帮助

时间:2010-04-09 13:49:14

标签: select mysql

我表达了记录和搜索标签之间的关系,可以附加到这样的记录:

TABLE RECORDS
id
name

TABLE SEARCHTAGS 
id
recordid
name

我希望能够根据他们拥有的搜索标签来选择记录。例如,我希望能够选择所有具有searchtags的记录:

(1 OR 2 OR 5) AND (6 OR 7) AND (10)

使用上面的数据结构,我不确定如何构造SQL来实现这一目标。

有什么建议吗?

谢谢!

6 个答案:

答案 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子句。