开发者

SQL Grouping By

开发者 https://www.devze.com 2023-01-25 18:49 出处:网络
Using ORACLE SQL. I have a table \'Employees\' with one of the attributes \'hire_date\' . My task (book exercise) is to write a SELECT that will show me how many employees were hired in 1995, 1996, 1

Using ORACLE SQL.

I have a table 'Employees' with one of the attributes 'hire_date' . My task (book exercise) is to write a SELECT that will show me how many employees were hired in 1995, 1996, 1997 and 1998 .

Something like:

TOTAL     1995     1996     1997     1998
-----------------------------------------
20        4        5        29       2

Individually is easy to count the number of employees for every year, eg:

SELECT
  COUNT(*),
FROM
  开发者_高级运维employees e
WHERE
  e.hire_date like '%95'

But I am having difficulties when I have to 'aggregate' the data in the needed format . Any suggestions ?


I'm assuming your hire_date is a varchar2, since you are doing a "like" clause in your example.

Will a simple table with one row per year do?

If so, try this in Oracle:

select case grouping(hire_date)
            when 0 then hire_date
            else 'TOTAL'
       end hire_date,
       count(hire_date) as count_hire_date
 from employees
 group by rollup(hire_date);

That should give something like:

hire_date  count_hire_date
1995       10
1996       20
1997       30
TOTAL      60

If you do need to pivot your results into something like you've shown in your question, then you can do the following if you know the distinct set of years prior to running the query. So for example, if you knew that you only had 1995, 1996 and 1997 in your table, then you could pivot the results using this:

SELECT
  MAX(CASE WHEN hire_date = 'TOTAL'    THEN ilv.count_hire_date   END) total,
  MAX(CASE WHEN hire_date = '1995'     THEN ilv.count_hire_date   END) count_1995,
  MAX(CASE WHEN hire_date = '1996'     THEN ilv.count_hire_date   END) count_1996,
  MAX(CASE WHEN hire_date = '1997'     THEN ilv.count_hire_date   END) count_1997
from (
    select case grouping(hire_date)
             when 0 then hire_date
             else 'TOTAL'
           end hire_date,
           count(hire_date) as count_hire_date
    from employees
    group by rollup(hire_date)
  ) ilv;

This has the obvious disadvantage of you needing to add a new clause into the main select statement for each possible year.


The syntax is not intuitive. This leverages cut'n'paste coding:

SQL> select
  2      sum(case when to_char(hiredate, 'YYYY') = '1980' then 1 else 0 end) as "1980"
  3      , sum(case when to_char(hiredate, 'YYYY') = '1981' then 1 else 0 end) as "1981"
  4      , sum(case when to_char(hiredate, 'YYYY') = '1982' then 1 else 0 end) as "1982"
  5      , sum(case when to_char(hiredate, 'YYYY') = '1983' then 1 else 0 end) as "1983"
  6      , sum(case when to_char(hiredate, 'YYYY') = '1987' then 1 else 0 end) as "1987"
  7      , count(*) as total
  8  from emp
  9  /

      1980       1981       1982       1983       1987      TOTAL
---------- ---------- ---------- ---------- ---------- ----------
         1         10          1          0          2         20

Elapsed: 00:00:00.00
SQL>


Here's how I'd do it in MySQL, don't know if this applies to Oracle too:

SELECT
 YEAR(hire_date), COUNT(*)
FROM 
 employees
GROUP BY 
 YEAR(hire_date)


SELECT NVL(hire_date,'Total'), count(hire_date) 
   FROM Employees GROUP BY rollup(hire_date);

If you need to PIVOT the data see A_M's answer. If you have years for which you have no data, yet still want the year to show up with a zero count you could do something like the following:

SELECT NVL(a.Year,b.Year), NVL2(a.Year,a.Count,0) FROM
(
SELECT NVL(hire_date,'Total') Year, count(hire_date) Count
   FROM Employees GROUP BY rollup(hire_date)
) a
FULL JOIN
(
   SELECT to_char(2000 + rownum,'FM0000') Year FROM dual CONNECT BY rownum<=9
) b ON a.Year = b.Year;

Here is some test data.

create table Employees (hire_date Varchar2(4));

insert into Employees values ('2005');
insert into Employees values ('2004');
insert into Employees values ('2006');
insert into Employees values ('2009');
insert into Employees values ('2009');
insert into Employees values ('2005');
insert into Employees values ('2004');
insert into Employees values ('2006');
insert into Employees values ('2006');
insert into Employees values ('2006');


Here's how I would do it in MS SQL - it will be similar in Oracle, but I don't want to try to give you Oracle code because I don't usually write it. This is just to get you a basic skeleton.

Select
  Year(e.hire_date),
  Count(1)
From
  employees e
Group By
  Year(e.hire_date)


I realize this is 6 years ago, but I also found another unique way of doing this using the DECODE function in Oracle.

select
count(decode(to_char(hire_date, 'yyyy') , '2005', hire_date, null)) hired_in_2005,
count(decode(to_char(hire_date, 'yyyy') , '2006', hire_date, null)) hired_in_2006,
count(decode(to_char(hire_date, 'yyyy') , '2007', hire_date, null)) hired_in_2007,
count(*) total_emp
from employees 
where to_char(hire_date,'yyyy') IN ('2005','2006','2007')
0

精彩评论

暂无评论...
验证码 换一张
取 消