Oracle - 由连接表组成

时间:2014-03-20 19:51:52

标签: sql oracle group-by

我试图寻找答案,我找到了更多的建议,但其中没有人对此有所帮助,所以我现在试着问。

我有两个表,一个是分销商(列:distributorid,名称),第二个是交付产品(列:distributorid,productid,corruptcount,date) - 列corruptcount包含损坏的交付数量。我需要在过去两个月中选择前五个经销商损坏最多的经销商。我需要选择distributorid,名称和corruptcount的总和,这是我的查询:

SELECT del.distributorid, d.name, SUM(del.corruptcount) AS corrupt FROM distributor d, delivery del WHERE d.distributorid = del.distributorid AND d.distributorid IN (SELECT distributorid FROM (SELECT distributorid, SUM(corruptcount) AS corrupt FROM delivery WHERE storeid = 1 AND "date" BETWEEN ADD_MONTHS(SYSDATE, -2) AND SYSDATE AND ROWNUM <= 5 GROUP BY distributorid ORDER BY corrupt DESC)) GROUP BY del.distributorid

但Oracle返回错误消息:“不是GROUP BY表达式”。

当我编辑我的查询时:

SELECT del.distributorid, d.name, del.corruptcount-- , SUM(del.corruptcount) AS corrupt FROM distributor d, delivery del WHERE d.distributorid = del.distributorid AND d.distributorid IN (SELECT distributorid FROM (SELECT distributorid, SUM(corruptcount) AS corrupt FROM delivery WHERE storeid = 1 AND "date" BETWEEN ADD_MONTHS(SYSDATE, -2) AND SYSDATE AND ROWNUM <= 5 GROUP BY distributorid ORDER BY corrupt DESC)) --GROUP BY del.distributorid

它按预期工作并返回正确的数据:
1 IBM 10 2 DELL 0 2 DELL 1 2 DELL 6 3 HP 3 8 ACER 2 9 ASUS 1

我想将这些数据分组。我的查询在哪里以及为什么错了?你能帮帮忙吗?非常感谢你。

1 个答案:

答案 0 :(得分:1)

我认为问题只是d.name列表中的select;您还需要将其包含在group by子句中。试试这个:

SELECT del.distributorid, d.name, SUM(del.corruptcount) AS corrupt
FROM distributor d join
     delivery del
     on d.distributorid = del.distributorid
WHERE d.distributorid IN
             (SELECT distributorid
              FROM delivery
              WHERE storeid = 1 AND
                    "date" BETWEEN ADD_MONTHS(SYSDATE, -2) AND SYSDATE AND
                    ROWNUM <= 5
              GROUP BY distributorid
              ORDER BY SUM(corruptcount) DESC
             ) 
GROUP BY del.distributorid, d.name;

我还使用join子句将查询切换为使用显式on语法,而不是使用join中的条件使用过时的隐式where语法。

我还删除了额外的子查询层。这不是必要的。

编辑:

“为什么d.name必须包含在group by中?”答案很简单,SQL需要它,因为它不知道要从组中包含哪个值。例如,您可以在min(d.name)中使用select,而无需更改group by子句。

真正的答案是有点复杂。 ANSI标准实际上允许在编写时进行查询。这是因为id(可能)被声明为表中的主键。当您按主键(或唯一键)进行分组时,您可以像使用同一个表一样使用其他列。虽然ANSI支持这一点,但大多数数据库还没有。因此,真正的原因是Oracle不支持允许查询工作的ANSI标准功能。