oracle dbms max возвращает все значения

#sql #oracle #select #max #aggregate-functions

#sql #Oracle #выберите #макс #агрегатные функции

Вопрос:

Я пытаюсь выполнить следующий запрос в базе данных Oracle express edition.

 SELECT SIGHTING_ID, MAX(DISTANCE)
FROM
(
    SELECT SIGHTING_ID,
          SQRT(POWER(LATITUDE   28, 2)   POWER(LONGITUDE - 151, 2)) AS DISTANCE
    FROM SIGHTINGS
)
GROUP BY SIGHTING_ID;
 

Цель запроса — вернуть идентификатор объекта НАБЛЮДЕНИЯ и РАССТОЯНИЕ для объекта наблюдения с максимальным расстоянием от координат (-28, 151)

Описание для ПРОСМОТРА таблицы выглядит следующим образом

  desc SIGHTINGS
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 SIGHTING_ID                               NOT NULL NUMBER
 SPOTTER_ID                                         NUMBER
 BIRD_ID                                            NUMBER
 LATITUDE                                           NUMBER
 LONGITUDE                                          NUMBER
 SIGHTING_DATE                                      DATE
 DESCRIPTION                                        VARCHAR2(255)
 

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

  SIGHTING_ID MAX(DISTANCE)
 ----------- -------------
 264172    2.01556444
 264174    2.34029913
 264180    2.87647354
 264198    .637887137
 264205    2.08568933
 264211    .232594067
 264215    2.34104677
 264221           .75
 264224    .148660687
 264235    .684470598
 

Мой вопрос в том, как мне сделать так, чтобы агрегатная функция MAX работала так, чтобы она возвращала только максимальное расстояние и относительный SIGHTING_ID?

Ответ №1:

Используйте Oracle rownum :

 SELECT * FROM 
    (SELECT SIGHTING_ID, SQRT(POWER(LATITUDE   28, 2)   POWER(LONGITUDE - 151, 2)) AS DISTANCE
     FROM SIGHTINGS
     ORDER BY distance DESC)
WHERE ROWNUM = 1
 

Причина, по которой вы получаете запись для каждого SIGHTING_ID , заключается в том, что вы группируете по ней. Предложение group by означает -> дайте мне 1 запись для каждой комбинации столбцов, упомянутых внутри предложения .

Комментарии:

1. Если есть две записи с максимальным расстоянием, то в этом случае одна из записей будет пропущена.

2. И откуда ты знаешь, что это не то, чего он хочет? @hemalp108

3. Я не сомневаюсь в вашем ответе, пусть он сам решает, чего он хочет. Я просто спрашиваю об этом из любопытства.

4. Большое вам спасибо, после удаления дополнительной скобки все прошло как по маслу

5. @FrankSchmitt — Вы снова правы. Еще недостаточно кофе!

Ответ №2:

В Oracle 12c можно использовать стандартную функциональность ANSI:

 SELECT SIGHTING_ID,
      SQRT(POWER(LATITUDE   28, 2)   POWER(LONGITUDE - 151, 2)) AS DISTANCE
FROM SIGHTINGS
ORDER BY distance DESC
FETCH FIRST 1 ROW ONLY;
 

В более ранних версиях решение @sagi, вероятно, является лучшим способом.

Комментарии:

1. Правильным решением для такого рода проблем является первая / последняя агрегатная функция (как я демонстрирую в своем ответе). docs.oracle.com/cd/B19306_01/server.102/b14200/functions056.htm

2. @mathguy Ваша формулировка вводит в заблуждение. Ваш подход является одним из нескольких правильных решений — Гордон Линофф — еще одно, а саги — еще одно.

3. @FrankSchmitt — Вы правы, я должен был сказать «лучший», а не «правильный». Для Oracle 12c решение Гордона одинаково хорошо; я не согласился с его оценкой для более ранних версий. Я бы отредактировал свои комментарии, но дальше это невозможно.

4. @mathguy . . . Я предпочитаю решение Саги, потому что оно легче обобщается на несколько столбцов (или все столбцы в строке).

Ответ №3:

 select min(sighting_id) keep (dense_rank first order by distance) as sighting_id,
       min(distance)                                              as distance
from sightings;
 

Это позволит найти строку или строки с самым коротким distance , и из этих строк (и только из них), если есть связи (самый короткий distance достигается двумя или более sighting id ‘s), он выбирает строку с наименьшим sighting_id . Если вместо этого вы хотите, чтобы значение было наибольшим latitude (скажем), по-прежнему из тех, у которых наименьшее distance , измените order by distance на order by distance, latitude desc . Другие комбинации обрабатываются таким же образом.