Проблема с SQLite SQL Query

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

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

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

SQLSTATE [HY000]: общая ошибка: 1 требуется предложение GROUP BY перед 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;

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


person Alix Axel    schedule 20.01.2010    source источник


Ответы (4)


Вы не можете указать предложение 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;

Если вы не хотите вызывать DISTANCE более одного раза, вы можете использовать подзапрос:

  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;
person OMG Ponies    schedule 20.01.2010
comment
Но я попытался указать предложение GROUP BY... Есть ли способ запустить запрос без двойного вызова функции DISTANCE? Это значительно ускорит выполнение запроса. - person Alix Axel; 20.01.2010
comment
Хм... Я тоже не большой поклонник вложенных запросов, стр. 8 arubin.org /files/geo_search.pdf намного проще. Руководство по MySQL (dev.mysql.com/doc /refman/5.0/en/group-by-hidden-columns.html) говорит, что стандарт SQL не позволяет предложению HAVING называть любой столбец, который не найден в предложении GROUP BY, если он не заключен в агрегатная функция. Это специфично для SQLite? Извините за то, что я PITA, но есть ли другой способ обойти это? - person Alix Axel; 20.01.2010
comment
@Alix: Нет других вариантов минимизировать количество использований DISTANCE. DISTANCE не является агрегатной функцией, поэтому сравнение относится к предложению WHERE. Единственная причина использовать HAVING заключается в том, что вы фактически группируете записи, что маловероятно для таблицы стран. - person OMG Ponies; 20.01.2010

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

SELECT * FROM Locations WHERE abs(широта - 51,123) ‹ 0,12 AND abs(долгота - 0,123) ‹ 0,34 ORDER BY DISTANCE(широта, долгота, 51,123, 0,123)

...где (51,123, 0,123) — центральная точка широты/долготы, относительно которой вы ищете, а значения 0,12 и 0,34 используются для сужения вашего поиска до широты/долготы квадрата на сфере подходящего размера (т. е. квадрат n километров на n километров в этой точке земной сферы, где размер зависит от среднего географического распределения ваших местоположений). Я использую формулы длины в градусах из http://en.wikipedia.org/wiki/Longitude. для выяснения, какие эти значения должны быть заданы положением точки поиска на земной сфере.

person Dave Addey    schedule 20.01.2010
comment
Спасибо. Я делаю это, я просто не публиковал, чтобы не добавлять слишком много беспорядка. знак равно - person Alix Axel; 21.01.2010

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

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

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

person chirag    schedule 20.01.2010
comment
Спасибо, я этого не знал. Есть ли способ переписать запрос так, чтобы он возвращал только записи, содержащие distance <= ?, без двойного вызова функции DISTANCE? - person Alix Axel; 20.01.2010

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

 SELECT *, 
         DISTANCE(latitude, longitude, ?, ?) AS dist
    FROM COUNTRY c
   WHERE c.id NOT LIKE ?
     AND dist <= ?
ORDER BY dist;
person SimonDavies    schedule 22.02.2010
comment
Взгляните на последний фрагмент кода моего вопроса... - person Alix Axel; 22.02.2010