2011-04-29 70 views
4

我正在查询Oracle 10g中的报表。SQL查询自加入

我需要生成每个课程的简短列表以及过去一年提供的次数(包括实际未提供的次数)。

我创建一个查询

SELECT coursenumber, count(datestart) AS Offered 
FROM class 
WHERE datestart BETWEEN (sysdate-365) AND sysdate 
GROUP BY coursenumber; 

将会产生

COURSENUMBER OFFERED 
----   ---------- 
ST03    2 
PD01    1 
AY03    2 
TB01    4 

此查询正确的。但理想情况下,我希望它在左列中列出COURSENUMBER HY和CS以及0或null作为OFFERED值。我有一种感觉,这涉及到各种各样的连接,但到目前为止,我所尝试过的不会产生没有提供任何东西的类。

表通常看起来像

REFERENCE_NO DATESTART TIME TIME  EID  ROOMID COURSENUMBER 
------------ --------- ---- ---- ---------- ---------- ---- 
     256 03-MAR-11 0930 1100   2   2 PD01 
     257 03-MAY-11 0930 1100   12   7 PD01 
     258 18-MAY-11 1230 0100   12   7 PD01 
     259 24-OCT-11 1930 2015   6   2 CS01 
     260 17-JUN-11 1130 1300   6   4 CS01 
     261 25-MAY-11 1900 2000   13   6 HY01 
     262 25-MAY-11 1900 2000   13   6 HY01 
     263 04-APR-11 0930 1100   13   5 ST03 
     264 13-SEP-11 1930 2100   6   4 ST03 
     265 05-NOV-11 1930 2100   6   5 ST03 
     266 04-FEB-11 1430 1600   6   5 ST03 
     267 02-JAN-11 0630 0700   13   1 TB01 
     268 01-FEB-11 0630 0700   13   1 TB01 
     269 01-MAR-11 0630 0700   13   1 TB01 
     270 01-APR-11 0630 0700   13   1 TB01 
     271 01-MAY-11 0630 0700   13   1 TB01 
     272 14-MAR-11 0830 0915   4   3 AY03 
     273 19-APR-11 0930 1015   4   3 AY03 
     274 17-JUN-11 0830 0915   14   3 AY03 
     275 14-AUG-09 0930 1015   14   3 AY03 
     276 03-MAY-09 0830 0915   14   3 AY03 

回答

1

我觉得这样的事情应该为你工作,通过只是在做它作为一个子查询。

SELECT distinct c.coursenumber, 
     (SELECT COUNT(*) 
     FROM class 
     WHERE class.coursenumber = c.coursenumber 
      AND datestart BETWEEN (sysdate-365) AND sysdate 
     ) AS Offered 
FROM class c 
+0

非常感谢!我不知道你可以有一个子查询作为声明的选择x,y,z部分的一部分。 – tyh 2011-04-29 15:21:41

+0

@timyh没问题,很高兴我能帮忙,并欢迎来到SO。 – 2011-04-29 15:35:43

1

我喜欢jschoen的回答这种特殊情况下更好的(当你想要一个且只有一个行和列出来的子查询为主查询的每一行),但只是为了展示另一种方式来做到这一点:

select t1.coursenumber, nvl(t2.cnt,0) 
from class t1 left outer join (
select coursenumber, count(*) cnt 
from class 
where datestart between (sysdate-365) AND sysdate 
group by coursenumber 
) t2 on t1.coursenumber = t2.coursenumber 
+0

你介意解释nvl(t2.cnt,0)部分吗?我认为你指的是t2.cnt,但“nvl”是做什么的,最后的“0”的意义是什么? – tyh 2011-04-29 16:02:04

+0

@timyh:你说这是Oracle,对吧?那么,nvl()是一个Oracle函数。其他一些数据库也有,或者至少类似。 – runrig 2011-04-30 05:09:36

2
SELECT 
    coursenumber, 
    COUNT(CASE WHEN datestart BETWEEN (sysdate-365) AND sysdate THEN 1 END) AS Offered 
FROM class 
GROUP BY coursenumber; 

所以,你可以看到,这个特定的问题并不需要一个连接。

+0

也是一个工作解决方案。 “THEN 1 END”是做什么的? – tyh 2011-04-29 18:59:58

+0

它是[CASE](http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/expressions004.htm)表达式的一部分。基本上,CASE表达式如下所示:'CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... ELSE default_result END'。 'ELSE'部分是可选的,省略时默认为'ELSE NULL'。在我的例子中1是一个任意值,我可以使用任何东西,而不是NULL,因为COUNT不计数NULL。因此,CASE在条件为真时返回一个值,并计算该值。当条件为false时,返回NULL(不计数)。 – 2011-04-29 19:10:01