0

我有以下表格:

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 每行仅出现一次。

我想做一个查询,从content表中选择与给定标签集(以及所有相关标签)关联的所有行。例如,“获取所有与标签“新闻”和“医疗保健”相关联的内容行。

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

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.

4

2 回答 2

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 表。

于 2013-04-01T16:22:11.247 回答
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)
于 2013-04-01T16:22:19.177 回答