是否可以在t-sql中对组进行子查询?

时间:2011-07-30 21:39:31

标签: tsql group-by subquery

我的目标是编写一个查询,返回包含3个标志字段的所有类别,如下所示:

ID |恩|茹| FR

语言标志必须为ON或OFF,具体取决于是否与该类别相关联的课程记录。

我目前的陈述是:

SELECT c.ID,
    (CASE WHEN c.ID IN (SELECT c.ID FROM Lessons AS l WHERE l.Category_Id = c.ID AND l.Language_Id = 1) THEN 1 ELSE 0 END) AS En,
    (CASE WHEN c.ID IN (SELECT c.ID FROM Lessons AS l WHERE l.Category_Id = c.ID AND l.Language_Id = 2) THEN 1 ELSE 0 END) AS Ru,
    (CASE WHEN c.ID IN (SELECT c.ID FROM Lessons AS l WHERE l.Category_Id = c.ID AND l.Language_Id = 3) THEN 1 ELSE 0 END) AS Fr
FROM LessonCategories AS c

问题是这个查询非常慢,因为Lessons表有超过60,000条记录,而且我已经运行了3次。

我正在寻找一种方法来提高查询效率。 我想过在分类和课程之间使用分组,但我不确切知道如何以及它是否可能。

更快速查询的伪代码是:

SELECT c.[ID], 
    COUNT(l.Language_Id = 1) > 0 AS En
    COUNT(l.Language_Id = 2) > 0 AS Ru
    COUNT(l.Language_Id = 3) > 0 AS Fr
FROM CategoryTreeView AS c
INNER JOIN Lessons AS l ON l.Category_Id = c.ID
GROUP BY c.[ID]

有可能使用有效的t-sql表达这个吗? 或者是处理这种查询的更好方法吗?

P.S。如果它有帮助,我不关心得到一个按位标志字段而不是3个语言字段。

感谢。

4 个答案:

答案 0 :(得分:1)

嗯,你只需要结合你的两个查询;)

SELECT c.ID, 
       SUM(case when l.Language_Id = 1 then 1 else 0) AS En
       SUM(case when l.Language_Id = 2 then 1 else 0) AS Ru
       SUM(case when l.Language_Id = 3 then 1 else 0) AS Fr
FROM CategoryTreeView AS c
INNER JOIN Lessons AS l ON l.Category_Id = c.ID
GROUP BY c.ID

答案 1 :(得分:0)

试试这个

SELECT c.ID,
    (CASE WHEN l.Language_Id = 1 THEN 1 ELSE 0 END) AS En,
    (CASE WHEN l.Language_Id = 2 THEN 1 ELSE 0 END) AS Ru,
    (CASE WHEN l.Language_Id = 3 THEN 1 ELSE 0 END) AS Fr
FROM LessonCategories AS c
INNER JOIN Lessons l ON c.ID = l.CategoryId

顺便说一句, 目前,您正在通过应用SELECT语句对CASE子句进行过滤。通过将过滤语句移动到WHERE之前执行的SELECT子句,可以显着提高任何查询的性能。

答案 2 :(得分:0)

你可以在第二个例子中使用计数:

COUNT(case when l.Language_Id = 1 then 1 else null end) as EnCount
COUNT(case when l.Language_Id = 2 then 1 else null end) as RuCount

但实际上,您希望在第一个示例中使用exists

case when exists(SELECT 0 FROM Lessons AS l WHERE l.Category_Id = c.ID AND l.Language_Id = 1) then 1 else 0 end as En

通过适当的索引,三个exists将更快。

答案 3 :(得分:0)

一种完全不同的方法尝试转轴。

DECLARE @ctw TABLE(id int, languageid int) 

insert @ctw values(1,1)
insert @ctw values(1,1)
insert @ctw values(1,2)
insert @ctw values(1,3)
insert @ctw values(2,1)
insert @ctw values(2,3)

SELECT * FROM 
(
SELECT id, CASE languageid WHEN 1 THEN 'en' WHEN 2 THEN 'ru' WHEN 3 THEN 'fr' END language
FROM @ctw) a
PIVOT
(count(language) 
FOR language
in([en],[ru],[fr]) 
)AS p ORDER BY id

测试在这里http://data.stackexchange.com/stackoverflow/q/107960/

相关问题