2013-06-26 2 views
3

Итак, у меня проблема с SQL Query.Как использовать функцию MAX в трех таблицах?

Речь идет о получении данных о погоде для городов Германии. У меня есть 4 таблицы: staedte (города с основным ключом loc_id), gehoert_zu (содержит ключ города и ключ метеостанции, ближайшей к этому городу (station_id)), wettermessung (содержит всю информацию о погоде и информацию о станции ключевое значение) и wetterstation (содержит ключ и местоположение станций). И я использую PostgreSQL

Вот как таблица выглядит следующим образом:

wetterstation 
s_id[PK] standort lon lat hoehe 
---------------------------------------- 
10224  Bremen  53.05 8.8 4 


wettermessung 
stations_id[PK] datum[PK]  max_temp_2m ...... 
---------------------------------------------------- 
10224    2013-3-24  -0.4 


staedte 
loc_id[PK] name lat lon 
------------------------------- 
15   Asch 48.4 9.8 


gehoert_zu 
loc_id[PK] stations_id[PK] 
----------------------------- 
15   10224 

То, что я пытаюсь сделать, это получить название города с (например) самым высокой температурой при (может быть целый месяц или день). Поскольку данные о погоде привязаны к станции, мне действительно нужно получить идентификатор станции, а затем просто выбрать один из соответствующих городов станции. Возможный вопрос: «В каком городе он был самым жарким в июне?» и, скажем, самая высокая измеренная температура была на станции номер 10224. В результате я хочу получить город Аш. То, что я получил до сих пор это

SELECT name, MAX (max_temp_2m) 
FROM wettermessung, staedte, gehoert_zu 
WHERE wettermessung.stations_id = gehoert_zu.stations_id 
    AND gehoert_zu.loc_id = staedte.loc_id 
    AND wettermessung.datum BETWEEN '2012-8-1' AND '2012-12-1' 
GROUP BY name 
ORDER BY MAX (max_temp_2m) DESC 
LIMIT 1 

Есть две проблемы, связанные с результатами: 1) он принимает Waaaay слишком долго. Таблицы не такие большие (в городах есть около 70 тыс. Записей), но для достижения этой цели требуется от 1 до 7 минут. (44) правый.

Надеюсь, мне удалось достаточно ясно объяснить мою проблему, и я был бы рад за любую помощь. Заранее спасибо ! : D

+2

Вы используете 'LIMIT 1', поэтому вы всегда будете возвращать одну строку, и вы заказываете данные с помощью' max', поэтому вы всегда будете возвращать одну и ту же строку. Если вы удалите 'LIMIT 1', вы получите все строки, которые вы ожидаете. – Taryn

+0

Ну, данные о погоде привязаны к станции, а затем к станции, поэтому у меня есть около 1000 городов для каждой станции. Если я удалю предел, я получаю все города, которые привязаны к этой станции, но данные одинаковы для всех из них. – smeshko

+1

Мое предложение состояло в том, чтобы отредактировать исходное сообщение с некоторыми примерами данных для каждой таблицы и желаемым результатом. – Taryn

ответ

1

Если вы хотите, чтобы получить максимальную температуру в город использовать это заявление:

SELECT * FROM (
    SELECT gz.loc_id, MAX(max_temp_2m) as temperature 
     FROM wettermessung as wm 
     INNER JOIN gehoert_zu as gz 
     ON wm.stations_id = gz.stations_id 
     WHERE wm.datum BETWEEN '2012-8-1' AND '2012-12-1' 
     GROUP BY gz.loc_id) as subselect 
    INNER JOIN staedte as std 
     ON std.loc_id = subselect.loc_id 
     ORDER BY subselect.temperature DESC 

Используйте это заявление, чтобы получить город с самой высокой температурой (только 1 город):

SELECT * FROM(
    SELECT name, MAX(max_temp_2m) as temp 
    FROM wettermessung as wm 
    INNER JOIN gehoert_zu as gz 
     ON wm.stations_id = gz.stations_id 
    INNER JOIN staedte as std 
     ON gz.loc_id = std.loc_id 
    WHERE wm.datum BETWEEN '2012-8-1' AND '2012-12-1' 
    GROUP BY name 
    ORDER BY MAX(max_temp_2m) DESC 
    LIMIT 1) as subselect 
ORDER BY temp desc 
LIMIT 1 

По соображениям производительности всегда используйте явные объединения как LEFT, RIGHT, INNER JOIN и избегайте использования объединений с разделенным именем таблицы, поэтому ваш sql serevr не должен угадывать ссылки на ваши таблицы.

+0

Эта группа ошибочна – Paparazzi

+0

спасибо, я ее исправил .. =) – 5im

+0

Да, это работает, но это дает мне ВСЕ максимальные значения со ВСЕХ станций. Есть ли способ найти наивысшее значение MAX и получить ТОЛЬКО этот? Я прошу в основном, потому что он работает почти 10 минут, и я получаю наивысшую ценность. И спасибо МНОГО за помощь! – smeshko

0

Это общий пример того, как получить элемент с наивысшим, самым низким, самым большим, самым маленьким, любым значением. Вы можете настроить его в своей конкретной ситуации.

select fred, barney, wilma 
from bedrock join 
(select fred, max(dino) maxdino 
from bedrock 
where whatever 
group by fred) flinstone on bedrock.fred = flinstone.fred 
where dino = maxdino 
and other conditions 
0

Предлагаю вам использовать согласованное соглашение об именах. Особые условия для таблиц, содержащих один элемент в строке, являются хорошим соглашением. Вы только стол разбиваете это staedte. Должно быть stadt.

И я предлагаю использовать station_id последовательно, а не s_id и stations_id.

Опираясь на эти помещения, за Ваш вопрос:

... получить название города с ...Самая высокая температура в указанную дату

SELECT s.name, w.max_temp_2m 
FROM (
    SELECT station_id, max_temp_2m 
    FROM wettermessung 
    WHERE datum >= '2012-8-1'::date 
    AND datum < '2012-12-1'::date  -- exclude upper border 
    ORDER BY max_temp_2m DESC, station_id -- id as tie breaker 
    LIMIT 1 
    ) w 
JOIN gehoert_zu g USING (station_id) -- assuming normalized names 
JOIN stadt  s USING (loc_id) 
  • Используйте явные JOIN условия для лучшей читаемости и технического обслуживания.

  • Используйте псевдонимы таблиц, чтобы упростить ваш запрос.

  • Используйте x >= a AND x < b, чтобы включить нижнюю границу и исключить верхнюю границу, которая является обычным прецедентом.

  • Агрегат сначала и выберите свою станцию ​​с максимальной температурой, прежде чем присоединяться к другим столам, чтобы получить название города. Гораздо проще и быстрее.

  • Вы не указали, что делать, если несколько коротких «смачивающих» связей на max_temp_2m в данный период времени. Я добавил station_id в качестве тай-брейка, а это означает, что станция с самым низким идентификатором будет выбрана последовательно, если есть несколько отборочных станций.