2012-04-14 3 views
0

Я написал простое веб-приложение, которое позволяет вам отмечать стенды блошиного рынка на карте google. Каждый стенд хранится в базе данных sqlite3 с указанием геолокации и другой информацией. Это CREATE заявление для таблицы стендов:Непоследовательные результаты запроса геолокации в SQL

CREATE TABLE stands (
id INTEGER PRIMARY_KEY, 
name TEXT, 
address TEXT, 
u REAL, 
v REAL, 
); 

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

CREATE TABLE cities 
(name TEXT PRIMARY_KEY, 
u_min REAL, 
u_max REAL, 
v_min REAL, 
v_max REAL); 

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

Вот некоторые примеры стендов:

592077673|Kierrätystori Rovaniemellä|Urheilukatu 1, 96100 Rovaniemi, Suomi|66.4978306921681|25.7220569153442 
1321495145|Kruununhaka|Liisankatu, 00170 Helsinki, Suomi|60.1742596|24.9555782  
571688977|Viikki asukastalo LAVAn edusta|Biologinkatu 5, 00790 Helsinki, Suomi|60.2342312|25.04058 
563089951|Hämeentie 156|Hämeentie 156, 00560 Helsinki, Suomi|60.2130467082539|24.9785856067459  
518892420|Joensuu - Ilosaari|Siltakatu 1, 80100 Joensuu, Finland|62.5990455742272|29.7706540507875 

и города:

Rovaniemi|66.4978306921681|66.4978306921681|25.7220569153442|25.7220569153442 
Helsinki|60.1577049447137|60.2556221042622|24.9216988767212|25.0662129772156 
Järvenpää|60.4513724|60.4513724|25.0819323000001|25.0819323000001 
Joensuu|62.5990455742272|62.5990653244875|29.7706540507874|29.7706540507875 
Vantaa|60.2731724937748|60.2731724937748|24.9571491285278|24.9571491285278 

Проблема у меня будет извлекая количество стендов в городах. До сих пор я использую следующий запрос:

SELECT cities.name AS city, 
    cities.u_min, 
    cities.u_max, 
    cities.v_min, 
    cities.v_max, 
    count(stands.id) AS count 
FROM cities 
LEFT OUTER JOIN stands 
    ON ((stands.u BETWEEN cities.u_min AND cities.u_max) 
    AND(stands.v BETWEEN cities.v_min AND cities.v_max)) 
GROUP BY cities.name; 

Это возвращает:

Helsinki|60.1577049447137|60.2556221042622|24.9216988767212|25.0662129772156|9 
**Joensuu|62.5990455742272|62.5990653244875|29.7706540507874|29.7706540507875|0** 
Järvenpää|60.4513724|60.4513724|25.0819323000001|25.0819323000001|1 
Rovaniemi|66.4978306921681|66.4978306921681|25.7220569153442|25.7220569153442|1 
Vantaa|60.2731724937748|60.2731724937748|24.9571491285278|24.9571491285278|1 

Который не является правильным, поскольку город по имени Йоэнсуу имеет 1 позицию в своих границах:

518892420|Joensuu - Ilosaari|Siltakatu 1, 80100 Joensuu, Finland|62.5990455742272|29.7706540507875 

Но следующий запрос возвращает ожидаемый стенд:

SELECT * FROM stands where u between 62.5990455742272 and 62.5990653244875 and v between 29.7706540507874 and 29.7706540507875; 

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

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

ответ

1

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

Один из подходов заключается в расширении границ в каждом запросе непосредственно:

SET @e = 0.0000000000001; 

SELECT cities.name AS city, 
    cities.u_min, 
    cities.u_max, 
    cities.v_min, 
    cities.v_max, 
    count(stands.id) AS count 
FROM cities 
LEFT OUTER JOIN stands 
    ON ((stands.u BETWEEN cities.u_min - @e AND cities.u_max + @e) 
    AND(stands.v BETWEEN cities.v_min - @e AND cities.v_max + @e)) 
GROUP BY cities.name; 

Другой подход заключается в хранении расширены границы в городах таблице:

SET @e = 0.0000000000001; 

UPDATE cities 
SET cities.u_min = cities.u_min - @e, 
    cities.u_max = cities.u_max + @e, 
    cities.v_min = cities.v_min - @e, 
    cities.v_max = cities.v_max + @e; 

P.S. Я не уверен, работает ли переменный синтаксис в SQLite, но если нет, просто замените все @e на 0.0000000000001.

+0

Это сработало довольно хорошо, спасибо вам, сэр! – Jonsku

+0

Нет, синтаксис SET не поддерживается sqlite. Я вручную исправил базу данных и модифицировал скрипт PHP, который обрабатывает транзакции базы данных, чтобы расширить границы при создании и обновлении. – Jonsku

+0

Я рад, что у вас это работает. –

0

Причина в том, что вы используете LEFT JOIN, поэтому он включает все города, независимо от того, существует ли соответствие в таблице stands. Обратите внимание, как COUNT возвращает 0 для этой строки.

Просто используйте INNER JOIN вместо LEFT JOIN. Это заставит MySQL только возвращать строки, для которых выполняется условие в ON.

UPD: Я неправильно понял вопрос, поэтому этот ответ неправильный. Я отправлю еще один ответ.

+0

Спасибо, но INNER JOIN не решает проблему. COUNT для строки Joensuu должен возвращать 1 не 0, потому что в границах города есть стойка (Lat: 62.5990455742272 - 62.5990653244875, Long: 29.7706540507874 - 29.7706540507875): ** 518892420 | Joensuu - Ilosaari | Siltakatu 1, 80100 Joensuu, Финляндия | 62.5990455742272 | 29.7706540507875 ** \ n Проблема находится где-то в состоянии ON, по какой-то причине стенд не подсчитывается. – Jonsku

Смежные вопросы