Синтаксис для подсчета большего и суммирования значения с несколькими объединениями без ключевого слова, имеющего - PullRequest
1 голос
/ 13 апреля 2020

Я учу 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

Для этого я был попытка сделать что-то немного более сложное: создать представление, в котором есть имя проекта, название отдела, количество сотрудников и общее количество часов, отработанных для каждого проекта, который имеет критерии более чем одного сотрудника. Я кое-что прочитал и сделал несколько основ c 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 BY и HAVING. Это хорошо для использования? Если нет, то что мне использовать?

Пожалуйста и спасибо.

Ответы [ 2 ]

1 голос
/ 14 апреля 2020

Этот способ немного более многословен, но исключает ключевое слово 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 решение тоже хорошо.

1 голос
/ 13 апреля 2020

Во-первых, вам нужно предложение 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, тогда вам не нужно DISTINCT в COUNT():

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
...