【问题标题】:Syntax for counting greater than and summing a value with multiple joins without the keyword having在没有关键字的情况下使用多个连接计算大于和求和的语法
【发布时间】:2020-04-13 18:28:58
【问题描述】:

我正在学习 SQL (Postgres),但我对我正在尝试做的事情有点困惑。

我有以下表格。员工:

  fname   | minit |  lname  |    ssn    |   bdate    |         address         | sex |  salary  | super_ssn | dno 
----------+-------+---------+-----------+------------+-------------------------+-----+----------+-----------+-----
 James    | E     | Borg    | 888665555 | 1937-11-10 | 450 Stone, Houston TX   | M   | 55000.00 |           |   1
 John     | B     | Smith   | 123456789 | 1965-01-09 | 731 Fondren, Houston TX | M   | 30000.00 | 333445555 |   5
 Franklin | T     | Wong    | 333445555 | 1955-12-08 | 638 Voss, Houston TX    | M   | 40000.00 | 888665555 |   5
 Alicia   | J     | Zelaya  | 999887777 | 1968-01-19 | 3321 Castle, Spring TX  | F   | 25000.00 | 987654321 |   4
 Jennifer | S     | Wallace | 987654321 | 1941-06-20 | 291 Berry, Bellaire TX  | F   | 43000.00 | 888665555 |   4
 Ramesh   | K     | Narayan | 666884444 | 1962-09-15 | 975 Fire Oak, Humble TX | M   | 38000.00 | 333445555 |   5
 Joyce    | A     | English | 453453453 | 1972-07-31 | 5631 Rice, Houston TX   | F   | 25000.00 | 333445555 |   5
 Ahmad    | V     | Jabbar  | 987987987 | 1969-03-29 | 980 Dallas, Houston TX  | M   | 25000.00 | 987654321 |   4

项目:

      pname      | pnumber | plocation | dnum 
-----------------+---------+-----------+------
 ProductX        |       1 | Bellaire  |    5
 ProductY        |       2 | Sugarland |    5
 ProductZ        |       3 | Houston   |    5
 Computerization |      10 | Stafford  |    4
 Reorganization  |      20 | Houston   |    1
 Newbenefits     |      30 | Stafford  |    4

部门:

     dname      | dnumber |  mgr_ssn  | mgr_start  
----------------+---------+-----------+------------
 Research       |       5 | 333445555 | 1988-05-22
 Administration |       4 | 987654321 | 1995-01-01
 Headquarters   |       1 | 888665555 | 1981-06-19

还有works_on:

   essn    | pno | hours 
-----------+-----+-------
 123456789 |   1 |  32.5
 123456789 |   2 |   7.5
 666884444 |   3 |  40.0
 453453453 |   1 |  20.0
 453453453 |   2 |  20.0
 333445555 |   2 |  10.0
 333445555 |   3 |  10.0
 333445555 |  10 |  10.0
 333445555 |  20 |  10.0
 999887777 |  30 |  30.0
 999887777 |  10 |  10.0
 987987987 |  10 |  35.0
 987987987 |  30 |   5.0
 987654321 |  30 |  20.0
 987654321 |  20 |  15.0
 888665555 |  20 |   0.0

为此,我尝试做一些稍微复杂的事情:创建一个视图,其中包含项目名称、部门名称、员工人数以及每个项目的总工作时数,并且每个项目都具有多个员工的标准.我读了一些书,做了一些基本的count(*)sum(*),但这里的语法让我很生气。

这是我经过数小时试图了解此语法的运作方式后得到的最远的结果:

SELECT 
p.pname AS "Project",
d.dname AS "Department",
count(w.essn) AS "# of Employees",
sum(w.hours) AS "Total Hours"
FROM project p JOIN works_on w
ON p.pnumber = w.pno 
JOIN department d
ON d.dnumber = p.dnum
WHERE w.essn > 1 

WHERE 子句显然是错误的。我想我的JOINS 是正确的。如何将这些聚合函数与所有这些连接正确地放在一起?我需要嵌套查询吗?我找到了一些使用HAVING 的示例,但我听说它是​​遗留的,并且想使用更新和新鲜的东西,但除了使用GROUP BYHAVING 之外没有找到其他示例。那些好用吗?如果没有,我应该使用什么?

请,谢谢。

【问题讨论】:

    标签: sql postgresql join group-by count


    【解决方案1】:

    首先,您需要一个GROUP BY 子句来使您的查询成为有效的聚合查询:该子句应包括所有非聚合列(我还添加了项目编号,以防两个项目具有相同的名称)。

    然后,您可以使用HAVING 子句来过滤拥有多名员工的项目:

    SELECT 
        p.pname AS "Project",
        d.dname AS "Department",
        COUNT(DISTINCT w.essn) AS "# of Employees",
        SUM(w.hours) AS "Total Hours"
    FROM project p 
    JOIN works_on w ON p.pnumber = w.pno 
    JOIN department d ON d.dnumber = p.dnum
    GROUP BY p.pname, d.dname, p.pnumber
    HAVING COUNT(DISTINCT w.essn) > 1
    

    如果(essn, number) 元组在works 表中是唯一的,那么您不需要COUNT() 中的DISTINCT

    SELECT 
        p.pname AS "Project",
        d.dname AS "Department",
        COUNT(*) AS "# of Employees",
        SUM(w.hours) AS "Total Hours"
    FROM project p 
    JOIN works_on w ON p.pnumber = w.pno 
    JOIN department d ON d.dnumber = p.dnum
    GROUP BY p.pname, d.dname, p.pnumber
    HAVING COUNT(*) > 1
    

    【讨论】:

    • 首先感谢您的回答!它澄清了我遇到的许多问题,并且我自己记录/学习这些问题具有挑战性。我的部分问题虽然没有得到回答,但与 HAVING 是一个遗留关键字有关,所以我正在寻找一种没有它的方法来实现这一目标。你知道如何做到这一点,即使这有潜在的问题吗?
    • HAVING 根本不是遗产!它是标准 SQL 的合法部分。我知道的所有数据库都实现了它,并将在未来继续这样做。
    • 嗯,很高兴知道。有很多信息指向许多方向,将它分开并正确理解它是一个挑战。再次感谢您的帮助!
    【解决方案2】:

    这种方式稍微有点冗长,但是去掉了having关键字,因为where子句在子查询聚合处理之后是有条件的。

    另外,因为您在聚合查询之外进行连接,所以它应该更快,因为它不必按另一个外部列分组。

    Select
        Project_Works.Project AS "Project"
        ,Project_Works.Empcnt AS "# of Employees"
        ,Project_Works.TotHrs AS "Total Hours"
        ,d.department AS "Department"
    FROM 
        (SELECT 
            p.pname Project
            ,p.pnumber Pnumber
            ,count(w.essn) EmpCnt
            ,sum(w.hours) TotHrs
        FROM 
            project p INNER JOIN works_on w ON p.pnumber = w.pno 
        GROUP BY
            p.pname,p.pnumber
        ) Project_Works
    
        LEFT JOIN department d on Project_Works.Pnumber = d.dnumber
    WHERE
        Project_Works.Empcnt > 1
    

    @GMB 解决方案也不错。

    【讨论】:

    • 谢谢,我去看看。您将如何测试不同查询的性能?
    猜你喜欢
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多