计算不同表中的行并按特定条件分组

Counting rows in different tables and grouping by a certain criteria

我有 3 个表:项目、组件、供应商。每个都有一个 id 列、city 列和一些其他列。

我想做的是计算每个城市有多少个项目、组件和供应商。

我试过的是:

SELECT p.city, COUNT(p.idp), COUNT(c.idc), COUNT(s.idf) FROM
Projects p, Components c, Suppliers s
GROUP BY p.city

在 运行 这个查询之后,我得到了不正确的值,几乎所有值都是相同的,如下所示:

我只为每个城市存储了一个项目、1 或 2 个组件和 1-3 个供应商,所以这些不是预期的结果

在寻找一些类似的已解决问题后,我想出了这段代码

SELECT p.city , p.nr_projects, c.nr_components, s.nr_suppliers
FROM 
(SELECT city, COUNT(idp) AS nr_projects
FROM Projects
GROUP BY city)
AS p
JOIN
(SELECT city, COUNT(idc) AS nr_components
FROM Components
GROUP BY city)
AS c
ON p.city=c.city
JOIN
(SELECT city, COUNT(idf) AS nr_suppliers
FROM Suppliers
GROUP BY city)
as f
ON p.city=f.city
GROUP BY p.city;

这给了我一个错误,说 SQL 命令没有正确结束。

我应该如何处理这个任务?

由于您不再在查询的顶层执行任何聚合,因此您不再需要 GROUP BY 子句。此外,对于 Oracle,您不能在 table 别名表达式中使用 AS。这应该有效:

SELECT p.city , p.nr_projects, c.nr_components, s.nr_suppliers
FROM 
    (SELECT city, COUNT(*) AS nr_projects
    FROM Projects
    GROUP BY city) p
JOIN
    (SELECT city, COUNT(*) AS nr_components
    FROM Components
    GROUP BY city) c ON p.city=c.city
JOIN
    (SELECT city, COUNT(*) AS nr_suppliers
    FROM Suppliers
    GROUP BY city) s ON p.city=s.city

请注意,如果一个城市可能没有项目、组件或供应商,那么您应该使用 FULL OUTER JOIN 代替 JOIN 以确保您仍然在输出中获得该城市的行。

另请注意,使用 COUNT(*) 比计算特定变量更有效(因为不需要检查 NULL 值)并且我已对查询进行了修改.

合并总数,然后合计。

这样,您还可以获得其中 1 个表格中缺失的城市的总数。
使用 INNER JOIN 时不会出现在结果中。 (但他们会 FULL JOIN

SELECT city, 
SUM(proj) AS projects, 
SUM(comp) AS components, 
SUM(supp) AS suppliers
FROM 
(
    SELECT city
    , COUNT(idp) AS proj
    , 0 AS comp
    , 0 AS supp
    FROM Projects
    GROUP BY city

    UNION ALL

    SELECT city, 0, COUNT(idc), 0
    FROM Components
    GROUP BY city

    UNION ALL

    SELECT city, 0, 0, COUNT(idf)
    FROM Suppliers
    GROUP BY city
) q
GROUP BY city
ORDER BY city