2010-01-20 3 views
2

Я пытаюсь выполнить следующий запрос в SQLite 3:Проблемы с SQLite SQL Query

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

Но я получаю следующее сообщение об ошибке:

SQLSTATE[HY000]: General error: 1 a GROUP BY clause is required before HAVING

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

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
GROUP BY "id" 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

И я также попытался это:

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
GROUP BY "distance" 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

Нет ошибок, но все записи были возвращены (даже те, которые имеют "distance" > ?). Я также пробовал:

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
    AND "distance" <= ? 
ORDER BY "distance" ASC; 

Тот же выпуск, все записи были возвращены. Я дважды проверял - расстояние правильно вычисляется ... Я не знаю, что не так с этим запросом, может кто-то мне помочь?

ответ

2

Вы не можете указать положение HAVING не указав пункт GROUP BY. Использование:

SELECT *, 
     DISTANCE(latitude, longitude, ?, ?) AS dist 
    FROM COUNTRY c 
    WHERE c.id NOT LIKE ? 
    AND DISTANCE(c.latitude, c.longitude, ?, ?) <= ? 
ORDER BY dist; 

Если вы не хотите, чтобы позвонить РАССТОЯНИЮ более чем один раз, вы можете использовать подзапрос:

SELECT x.* 
    FROM (SELECT c.*, 
       DISTANCE(latitude, longitude, ?, ?) AS dist 
      FROM COUNTRY c 
      WHERE c.id NOT LIKE ?) x 
    WHERE x.dist <= ? 
ORDER BY dist; 
+0

Но я попытался указать предложение 'GROUP BY' ... Есть ли способ запустить запрос без необходимости дважды использовать функцию DISTANCE? Это сделает запрос намного быстрее. –

+0

Hummm ... Я тоже не большой поклонник вложенных запросов, страница 8 из http://www.arubin.org/files/geo_search.pdf гораздо более проста. Руководство MySQL (http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html) говорит: «Стандарт SQL не позволяет предложению HAVING назвать любой столбец, который не найден в предложении GROUP BY, если он не заключен в агрегированную функцию ". Является ли этот SQLite конкретным? Извините за то, что я был PITA, но каким-то другим способом обойти это? –

+0

@Alix: Нет никаких других вариантов минимизации количества раз, когда вы используете 'DISTANCE'. 'DISTANCE' не является агрегированной функцией, поэтому сравнение принадлежит предложению' WHERE'. Единственная причина использования 'HAVING' заключается в том, что вы на самом деле группируете записи, что маловероятно для таблицы стран. –

0

его синтаксическую ошибку, вы должны использовать «группу,» при использовании имеющей причины,

запрос с группой по является выборку записей, имеющих («расстояния»>), потому что, есть правило базы данных, что в первую очередь он берет данные с совпадающими записями, тогда он будет выполнять группу на нем после того, как он будет фильтровать записи по причине. так что вы никогда не получите данные, имеющие («расстояние» <)

, пожалуйста, поправьте, если я ошибаюсь

+0

Спасибо, что я не знал, что. Есть ли способ переписать запрос так, чтобы он возвращал только записи с 'distance <=?' Без необходимости дважды называть функцию DISTANCE? –

1

Лучше (и быстрее) подход может уменьшить вниз отобранный набор перед применением ORDER BY. Я использую такой подход:

SELECT * FROM мест, где абс (широта - 51,123) < 0,12 и абс (Долгота - 0,123) < 0,34 ORDER BY DISTANCE (широта, долгота, 51,123, 0,123)

. где (51.123, 0.123) - точка центральной широты/долготы, которую вы ищете относительно, а значения 0.12 и 0.34 используются для сужения поиска до полутора длинного квадрата на шаре соответствующий размер (т. е. квадрат в n километрах на километры в этой точке земной сферы, где размер зависит от среднего географического распределения ваших местоположений). Я использую формулы длины длины от http://en.wikipedia.org/wiki/Longitude, чтобы определить, каким этим значениям должна быть задана позиция точки поиска в сфере Земли.

+0

Спасибо. Я делаю это, я просто не писал, чтобы не добавлять слишком много беспорядка. =) –

-2

В дополнение к правильной FLAGGED ответа выше, если вы не хотите, чтобы вызвать функцию DISTANCE в два раза, обратитесь к псевдониму в предложении WHERE, то есть:

SELECT *, 
     DISTANCE(latitude, longitude, ?, ?) AS dist 
    FROM COUNTRY c 
    WHERE c.id NOT LIKE ? 
    AND dist <= ? 
ORDER BY dist; 
+0

Взгляните на последний фрагмент кода моего вопроса ... –