在同一视图上具有不同条件的两个计数查询

时间:2018-01-02 17:36:04

标签: sql sql-server

我有一个包含3个表的数据库。

Employee(SSN, Fname, Lname, Salary)
Project(Pnumber, Pname, Plocation)
Works_on(Essn, Pno, Hours)

我想创建一个视图,为每个项目显示其名称(Pname),有多少员工在该项目上获得超过38,000(更多)的工资,以及从事该项目的员工获得的薪酬少于38k (减)。

我的appraoch

    create view compare as 
    (
       (select count(E.SSN) as More, P.Pname
        from Employee as E, Project as P, Works_on as W
        where E.Salary > 38000 and W.Pno = P.Pnumber and E.SSN = W.Essn 
        group by(P.Pname)) union 

       (select count(E.SSN) as Less, P.Pname
        from Employee as E, Project as P, Works_on as W
        where E.Salary < 38000 and W.Pno = P.Pnumber and E.SSN = W.Essn 
        group by(P.Pname))
    );

但它只显示(更多)col和项目名称。

5 个答案:

答案 0 :(得分:3)

如果您确定要采用视图方法,这可能对您有用

select p.Pname
, sum(case when e.Salary < 38000 then 1 else 0 end) as under_38_k
, sum(case when e.Salary > 38000 then 1 else 0 end) as over_38_k
from Works_on w
join Employee e on e.ssn = w.essn
join Project p on p.Pnumber = w.Pno
group by p.Pname
order by p.Pname asc --customize as needed

考虑:

  • 由于我们使用JOIN(INNER JOIN的缩写),因此不会在结果中显示没有指定员工的项目。切换到LEFT OUTER JOIN到Projects表,如果你想要显示那些以0作为值。

  • 制作正好38k的员工也不在结果范围内。通过更改两列中的一列的case语句,随意包含它们。

如果要在不重新定义视图的情况下使该限制可自定义,您可以定义一个将限制作为参数的函数,如下所示:

CREATE FUNCTION EmployeesEarnings(@limit int)  
RETURNS TABLE  
AS  
RETURN  
select p.Pname
, sum(case when e.Salary < @limit then 1 else 0 end) as under_limit
, sum(case when e.Salary > @limit then 1 else 0 end) as over_limit
, sum(case when e.Salary < @limit then 1 else 0 end) - sum(case when e.Salary > @limit then 1 else 0 end) as difference
from Works_on w
join Employee e on e.ssn = w.essn
join Project p on p.Pnumber = w.Pno
group by p.Pname

然后调用该函数就好像它是一个表:

select *
from EmployeesEarnings(38000)

答案 1 :(得分:2)

使用条件SUM代替COUNT

select
    SUM(CASE WHEN E.Salary >= 38000 THEN 1 ELSE 0 END) as More
,   SUM(CASE WHEN E.Salary < 38000 THEN 1 ELSE 0 END) as Less
,   P.Pname
from Employee as E
join Works_on as W ON E.SSN = W.Essn 
join Project as P ON W.Pno = P.Pnumber
group by(P.Pname)

请注意使用ANSI连接(您应该切换到ANSI语法)并使用>=代替>(否则{38}的Salary将无法计算。< / p>

答案 2 :(得分:1)

您误解了UNION的工作原理。 UNION组合了数据集,它不会向其中添加精确列;它使用第一个查询中提供的别名。因此,您的列Less将在列More的输出中包含它的值。如果要显示列列,请尝试向两个数据集添加值为NULL的列。另外,摆脱那些可怕的隐含的JOIN。使用JOINON

CREATE VIEW Compare AS
      SELECT COUNT(E.SSN) as More,
             NULL AS Less,
             P.Pname
      FROM Employee E
           JOIN Project P ON W.Pno = P.Pnumber
           JOIN Works_on W ON E.SSN = W.Essn 
      WHERE E.Salary > 38000 
      GROUP BY P.Pname
      UNION 
      SELECT NULL as More,
             COUNT(E.SSN) AS Less,
             P.Pname
      FROM Employee E
           JOIN Project P ON W.Pno = P.Pnumber
           JOIN Works_on W ON E.SSN = W.Essn 
      WHERE E.Salary < 38000 
      GROUP BY P.Pname;

然而,这可以简化为

CREATE VIEW Compare AS

      SELECT CASE WHEN E.Salary > 38000 THEN COUNT(E.SSN) END AS More,
             CASE WHEN E.Salary < 38000 THEN COUNT(E.SSN) END AS Less,
             P.Pname
      FROM Employee E
           JOIN Project P ON W.Pno = P.Pnumber
           JOIN Works_on W ON E.SSN = W.Essn 
      GROUP BY P.Pname;

答案 3 :(得分:0)

首先,视图可能不适合这种情况,因为数字38000可能会随着时间而改变。

其次,案例结构似乎适合这种情况。一般的想法是:

select case when salary >= 38000 then 'more' else 'less' end salaryRange
, count(*) employees
etc
group by case when salary >= 38000 then 'more' else 'less' end

答案 4 :(得分:0)

create view compare as
  select sum(case when Salary >= 38000 then 1 else 0 end) as More,
         sum(case when Salary <  38000 then 1 else 0 end) as Less,
         sum(case when Salary >= 38000 then 1 else -1 end) as Diff,
         Pname
    from Project join Works_on on Pno = Pnumber
    join Employee on SSN = Essn
    group by Pname;