Я попытался найти ответ и нашел еще несколько советов, но ни один из них не помог, поэтому я пытаюсь спросить сейчас.

У меня есть две таблицы: одна с дистрибьюторами (столбцы: Distributorid, name) и вторая с доставленными продуктами (столбцы: Distributorid, productid, correcount, date) - столбец correcount содержит количество поврежденных доставок. Мне нужно выбрать первых пять дистрибьюторов с самыми коррумпированными поставками за последние два месяца. Мне нужно выбрать дистрибьютор, имя и сумму коррумпированного числа, вот мой запрос:

<код> ВЫБЕРИТЕ del.distributorid, d.name, SUM (del.corruptcount) КАК повреждено ОТ дистрибьютора d, доставка del ГДЕ d.distributorid = del.distributorid И d.distributorid IN (ВЫБЕРИТЕ дистрибьютора ОТ (ВЫБРАТЬ идентификатор дистрибьютора, СУММ (коррумпированное число) КАК повреждено С доставки ГДЕ storeid = 1 И "дата" МЕЖДУ ADD_MONTHS (SYSDATE, -2) И SYSDATE И СТРОКА <= 5 ГРУППА ПО дистрибьютору ЗАКАЗАТЬ ПО коррумпированному DESC)) ГРУППА ПО del.distributorid

Но Oracle возвращает сообщение об ошибке: «не выражение GROUP BY».

И когда я редактирую свой запрос на это:

<код> ВЫБЕРИТЕ del.distributorid, d.name, del.corruptcount--, SUM (del.corruptcount) КАК повреждено ОТ дистрибьютора d, доставка del ГДЕ d.distributorid = del.distributorid И d.distributorid IN (ВЫБЕРИТЕ дистрибьютора ОТ (ВЫБРАТЬ идентификатор дистрибьютора, СУММ (коррумпированное число) КАК повреждено С доставки ГДЕ storeid = 1 И "дата" МЕЖДУ ADD_MONTHS (SYSDATE, -2) И SYSDATE И СТРОКА <= 5 ГРУППА ПО дистрибьютору ЗАКАЗАТЬ ПО коррумпированному DESC)) - ГРУППА ПО del.distributorid

Он работает так, как вы ожидаете, и возвращает правильные данные:
1 IBM 10 2 DELL 0 2 DELL 1 2 DELL 6 3 HP 3 8 ACER 2 9 ASUS 1

Я хочу сгруппировать эти данные. Где и почему мой запрос неверен? Не могли бы вы помочь? Огромное спасибо.

0
Honza 20 Мар 2014 в 23:51

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, которые позволили бы вашему запросу работать.

1
Gordon Linoff 21 Мар 2014 в 00:27
Спасибо за исправление моего запроса, я не знал об устаревшем синтаксисе неявного соединения и упорядочивании по SUM ... хорошая идея, спасибо. И почему d.name следует включать в предложение GROUP BY? Редактировать: Спасибо за объяснение. Oracle обнаружил одну ошибку, сортировка по сумме (коррумпированность) не работает, Oracle возвращает: «отсутствует правая скобка»
 – 
Honza
21 Мар 2014 в 00:52