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

问题描述 投票:2回答:5

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

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

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

我的方法

    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和项目名称。

sql sql-server
5个回答
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)

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语法)并使用>=代替>(否则3838的Salary将无法计算)。


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;

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

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;
© www.soinside.com 2019 - 2024. All rights reserved.