我试图寻找答案,我找到了更多的建议,但其中没有人对此有所帮助,所以我现在试着问。
我有两个表,一个是分销商(列: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
我想将这些数据分组。我的查询在哪里以及为什么错了?你能帮帮忙吗?非常感谢你。
答案 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标准功能。