2013-07-09 74 views
1

标题有点模糊,所以在这里。SQL-从共享两列值的表中获取所有记录

我有一个表:tag_tasks

它是重要的两列连接表:tag_idtask_id

我想获得有两个标签的任务数的计数。

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

我想有这些记录:

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),然后获得总计数(在这种情况下,我的最终目标是返回数字四)。

编辑 - RESULT SETS

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而不是24和30)。

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

+1

请在您的问题中显示最终结果。 –

+0

是mysql表吗? –

+0

这是一个mysql表。 – Squadrons

回答

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 Fiddle

变化SELECT *SELECT COUNT(*),如果你想返回,而不是实际的记录的记录数。或者,如果你只是想满足此条件task_ids的数量,使用SELECT COUNT(DISTINCT task_id)

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子句可以被回收用于一般选择以获得其他数据。

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 

this fiddle。如有任何问题,请发表评论。

+0

当我只有4条记录共享这两个tag_id时,这使我留下了余数 – Squadrons

1

好吧,我认为你想要的是显示与此外部参照表相关的任务记录到所有您感兴趣的标记。因此,具体而言,您希望所有具有标记任务跨任务的任务参考记录将任务绑定到标签24和标签30上。

这可能是最好用两个内部连接完成的,这两个连接都位于任务和标签任务之间。

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 

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

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

+0

我开始认为抓取比我需要的更多的记录,并且简单地在ruby中完成其余的记录看起来像是一个很好的选择,尽管用于学习目的我很想看看有人会如何在SQL中解决这个问题,以及了解什么时候某些东西在SQL中不值得做,并且在程序代码中变得更高效。 – Squadrons

+1

那么,过滤,排序,分组等等通常最好留给数据库。您要求的数据越多,代码中处理的代码就越多,而且您的代码要比平均数据库引擎固有的开发工作落后几十年(并希望在具有数据库服务器资源的十分之一的计算机上运行),所以无论你在代码中做什么,数据库服务器都可以做得更快。我会让数据库服务器尽可能地做到这一点,并根据需要返回尽可能少的数据。 – KeithS

+1

举例来说,此查询只会返回符合条件的唯一任务ID,而不会将它们加入到标记ID中。在数据带宽上有所节省。您需要做的所有事情就是让每个结果与您的每个标签都匹配成一个独特的行,并根据您将如何使用这些数据,甚至不需要这些数据。 – KeithS

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

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

1

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

肯定了“记录计数”给你,你要找的答案!

+0

它确实 - 但我最终有两个记录。显然是一个初学者的问题,但有没有办法简单地结束总记录数而不是行本身? – Squadrons

+0

您是否在使用某种应用程序级别的代码PHP的? – Strawberry

0

看起来好像你的SQLfiddle在你的编辑工作正常,如果你添加额外的过滤器的Tag_ID在最后,对不对?

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 */ 
相关问题