如何为子查询中的每一行添加WHERE子句?

时间:2013-04-01 16:13:49

标签: mysql sql

我有以下表格:

CREATE TABLE `content` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `content` varchar(255) NOT NULL,
  `tag_a_id` int unsigned DEFAULT NULL,
  `tag_b_id` int unsigned DEFAULT NULL,
  `tag_c_id` int unsigned DEFAULT NULL,
  `tag_d_id` int unsigned DEFAULT NULL,
  `tag_e_id` int unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `tags` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tag` varchar(32) NOT NULL UNIQUE,
  PRIMARY KEY (`id`)
);

tags表与内容表具有一对多关系,使用tag_?_id字段,但每个标记ID每行仅显示ONCE。

我想进行一个查询,在其中我从content表中选择与给定标记集(以及所有关联的标记)相关联的所有行。例如,“获取所有标记为”News“和”MedicalCare“的内容行。

这意味着需要在tags表中查找“News”和“MedicalCare”的ID,然后使用一对查询将其注入content表中的查询中这(假设这些标签具有ID 4568):

SELECT id FROM tags WHERE tag IN ("News","MedicalCare");

......然后......

SELECT t1.id, t1.content, ts_a.tag, ts_b.tag, ts_c.tag, ts_d.tag, ts_e.tag
FROM (
    SELECT t.id, t.content, t.tag_a_id, t.tag_b_id, t.tag_c_id, t.tag_d_id, t.tag_e_id
    FROM content t
    WHERE 45 IN (t.tag_a_id, t.tag_b_id, t.tag_c_id, t.tag_d_id, t.tag_e_id)
    AND 68 IN (t.tag_a_id, t.tag_b_id, t.tag_c_id, t.tag_d_id, t.tag_e_id)
    ORDER BY t.id ASC LIMIT 200
) t1
LEFT JOIN tags ts_a ON t1.tag_a_id=ts_a.id
LEFT JOIN tags ts_b ON t1.tag_b_id=ts_b.id
LEFT JOIN tags ts_c ON t1.tag_c_id=ts_c.id
LEFT JOIN tags ts_d ON t1.tag_d_id=ts_d.id
LEFT JOIN tags ts_e ON t1.tag_e_id=ts_e.id;

有没有办法可以在这个查询中获取我对感兴趣的标记ID,并动态生成那些AND x IN(a,b,c)子句?

另一种选择可能是:

WHERE EVERY ONE OF (
    SELECT id FROM tags WHERE tag IN ("News","MedicalCare")
) IN (t.tag_a_id, t.tag_b_id, t.tag_c_id, t.tag_d_id, t.tag_e_id)

请注意:content表非常大,因此将内容表连接到标记表是不可行的,而不先过滤掉不需要的行并应用LIMIT

2 个答案:

答案 0 :(得分:1)

如果您知道标签是唯一的,您可以执行以下操作:

where ((ts_a.tag in ('News', 'MecialCare')) +
       (ts_b.tag in ('News', 'MecialCare')) +
       (ts_c.tag in ('News', 'MecialCare')) +
       (ts_d.tag in ('News', 'MecialCare')) +
       (ts_e.tag in ('News', 'MecialCare'))
      ) = 2

这使用的事实是,在MySQL中,比较返回0或1,然后可以将它们加在一起。

顺便说一下,这个问题是为什么数据应该正确结构化的一个很好的理由,每个人的每个标签都有一个单独的行,一个persno_tag表。

答案 1 :(得分:1)

我认为这样做会:

select t1.id, t1.content, ts_a.tag, ts_b.tag, ts_c.tag, ts_d.tag, ts_e.tag
from content t1
LEFT JOIN tags ts_a ON t1.tag_a_id=ts_a.id
LEFT JOIN tags ts_b ON t1.tag_b_id=ts_b.id
LEFT JOIN tags ts_c ON t1.tag_c_id=ts_c.id
LEFT JOIN tags ts_d ON t1.tag_d_id=ts_d.id
LEFT JOIN tags ts_e ON t1.tag_e_id=ts_e.id
where "News" in (ts_a.tag, ts_b.tag, ts_c.tag, ts_d.tag, ts_e.tag)
and "MedicalCare" in (ts_a.tag, ts_b.tag, ts_c.tag, ts_d.tag, ts_e.tag)