1

标题有点模糊,就这样吧。

我有一张桌子:tag_tasks

它是一个具有两列重要性的连接表:tag_idtask_id

我想计算具有两个标签的任务数。

例如:我有一个task(id = 12)和一个tag(id = 24和另一个tag(id = 30)

在 tag_tasks 我会有这些记录:

tag_id  task_id
24      12
30      12

假设那里还有一些记录可以使它变得现实:

tag_id  task_id
24      12
30      12
36      43
24      45
56      98
24      115
30      115

仅当 task_id 与我的两个目标标签都关联时,我才想返回记录。在这种情况下,只有前两行 (task_id = 12) 和最后两行 (task_id = 115),然后得到一个总数(在这种情况下,我的最终目标是返回数字 4)。

编辑 - 结果集

tag_id  task_id
    24      12
    30      12
    24      115
    30      115

但最后我想得到这样的结果(上述结果的总和):

task_count_for_both_tags_combined
4

这对我来说有点令人困惑,所以如果我能澄清我的问题,请告诉我。

谢谢你。

编辑 - 到目前为止我的结果 这段代码让我很接近,但我需要添加结果数字 - *请注意,这只是当前数据集,可能有任意数量的行,我按 task_id 分组*

SELECT COUNT( task_id ) AS task_count, tag_id
FROM  `tag_tasks` 
WHERE tag_id
IN ( 15, 11 ) 
GROUP BY task_id
HAVING task_count >1

这给我留下了这个结果,我需要以下总和:

task_count  task_id 
2           34
2           45

编辑 - SQLFIDDLE 示例 我刚刚了解到这存在,所以这里是来自一张海报的不正确的小提琴答案,其数据集稍大。这个 sql 最终选择了与我想要的标签不同的记录(31 和 32 而不是 JUST 24 和 30)。

http://www.sqlfiddle.com/#!2/116f9/1/0

4

7 回答 7

1

好的,我认为您想要的是显示此外部参照表与您感兴趣的所有标签相关的任务记录。因此,具体来说,您希望所有具有标签任务交叉引用记录的任务都与任务到标签 24 和标签 30。

这可能最好通过 Task 和 Tag-Task 之间的两个内部连接来完成。

SELECT t.taskId --or COUNT(*)
FROM Task t
INNER JOIN TagTasks tt1
   ON tt1.taskId = t.taskId
   AND tt1.tagId = 24
INNER JOIN TagTasks tt2
   ON tt2.taskId = t.taskId
   AND tt2.tagId = 30

结果:

12
115

...如果您想要问题中定义的确切结果集,请修改选择并添加第三个联接:

SELECT tt3.tagId, t.taskId
FROM Task t
INNER JOIN TagTasks tt1
   ON tt1.taskId = t.taskId
   AND tt1.tagId = 24
INNER JOIN TagTasks tt2
   ON tt2.taskId = t.taskId
   AND tt2.tagId = 30
INNER JOIN TagTasks tt3
   ON tt3.taskId = t.taskId
   AND (tt3.tagId = 24 OR tt3.tagId = 30)

结果:

tag_id  task_id
24      12
30      12
24      115
30      115

当连接使用索引列(如主键字段)时,连接很便宜,因此此选择应该比 Exists 或其他子查询执行得更快。因为所有连接都是内连接,所以它们都必须匹配过滤器和连接标准,才能生成该组合的任何结果行。它也不应该产生笛卡尔连接,因为每个子句将匹配一个且仅一个标记 ID,因此您不会根据第一个连接匹配标记 24 在一行中然后在下一个标记 30 得到重复的结果。

然而,这不是一个容易作为存储过程自动化的查询。对于要搜索的每个标签,您都需要一个 Join,加上将为选择列表提供字段的 Join,因此几乎不可能以这种形式对单个查询进行硬编码,从而在不产生笛卡尔坐标的情况下执行您想要的操作连接等。但是,这个查询及其反复重复的样板部分,相对容易在应用程序代码中生成并通过线路发送到服务器(只是不要像往常一样内联最终用户输入的任何内容)。

于 2013-07-09T16:31:50.513 回答
1

尝试以下查询:

SELECT A.*
FROM tag_tasks AS A
INNER JOIN 
(
SELECT TASK_ID , COUNT(*) AS CNT
FROM tag_tasks
WHERE TAG_ID = 24 OR TAG_ID = 30
GROUP BY TASK_ID
) AS B ON A.TASK_ID = B.TASK_ID
WHERE B.CNT = 2

SQLFIDDLE

我使用了连接查询。与 EXIST 和 IN 子句相比,Join 提供了更好的性能,因为 Join 查询在执行时只运行一次,但 EXIST 和 IN 子句中的查询针对表中的每条记录运行,并且当我们有大量数据时需要更多时间来产生结果桌子 。

于 2013-07-09T16:34:23.220 回答
1

这应该这样做。

SELECT *
FROM tableName a
WHERE exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 24)
AND exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 30)

SQL小提琴

如果您想要返回的记录数而不是实际记录数,请更改SELECT *为。SELECT COUNT(*)或者,如果您只想满足此条件的 task_id 数量,请使用SELECT COUNT(DISTINCT task_id)

于 2013-07-09T16:26:00.390 回答
1

像这样的东西是否适用于计数部分:

select 2*count(task_id) where task_id in (select task_id where tag_id=24) and task_id in (select task_id where tag_id=30)

基本上,如果任务有两个标签,则将其添加到计数中并在最后加倍。where 子句可以循环用于一般选择以获取其他数据。

于 2013-07-09T16:26:04.533 回答
1

http://www.sqlfiddle.com/#!2/116f9/3

当然,“记录计数”会给你你正在寻找的答案!

于 2013-07-09T16:50:07.567 回答
1
select count(distinct(t1.task_id))-1 
from tag_tasks t1, tag_tasks t2 
where t1.task_id = t2.task_id 
    and t1.tag_id = t2.tag_id

就像在这个小提琴中一样。有任何问题,请发表评论。

于 2013-07-09T16:26:57.460 回答
0

如果您在最后添加 Tag_ID 的附加过滤器,您的编辑中的 SQLfiddle 似乎工作正常,对吧?

SELECT COUNT(*) 
FROM tableName a
WHERE exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 24)
AND exists( 
    select 1 
    from tableName b 
    where a.task_id = b.task_id
    and tag_id = 30)
AND (Tag_ID = 24 OR Tag_ID = 30) /* add this filter to exclude the IDs you don't want */
于 2013-07-09T19:43:14.440 回答