Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z zapytaniem - liczenie odległości w promieniu od punktu - Harvestine formula
Forum PHP.pl > Forum > Bazy danych > MySQL
Kulfon
Cześć! Męczę się i męczę i chyba nie dojdę do tego jak powinno to być...

Znalazłem/wymyśliłem kilka innych rozwiązań ale traktuję je póki co jako drogę na około, a nie prawdiłową drogę działania dlatego chciałbym zapytać jeszcze tutaj - moze uda się to zrobić jak należy, a nie na około.

Chcę liczyć odległość od punktu. Na to mamy odpowiedni wzór. Zapytanie do bazy też nie powinno przysparzać problemów ale tutaj sprawa się komplikuje. Otóż postawione na Wordpressie. I moje pytanie odnosi się tylko do zapytania. Tabela wygląda tak:
id post_id meta_key meta_value
640 11 lat 50.0952545
641 11 lng 20.078393600000027
642 11 address Kwiatowa 12
(tabela wp_postmeta)

Czyli ogólnie to co potrzebuję to:
- wyciągnąć z bazy wartości lat i lng
- policzyć dystans
- tam gdzie dystans jest mniejszy niż podany do zapytania zwrócić np. pole address

Na moment obecny mam takie coś:
  1. $wpdb->get_results(sprintf("SELECT meta_value, post_id, ( 3959 * acos( cos( radians('%s') ) * cos( radians( '%s' ) ) * cos( radians( '%s' ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( '%s' ) ) ) )
  2. AS distance FROM wp_postmeta HAVING distance < '%s' ORDER BY distance LIMIT 0 , 200",
  3. mysql_real_escape_string($center_lat), // podana przez usera lat
  4. $wpdb->get_var("SELECT meta_value FROM wp_postmeta WHERE meta_key = 'lat'"), //brana z bazy wartosc lat
  5. $wpdb->get_var("SELECT meta_value FROM wp_postmeta WHERE meta_key = 'lng'"), //brana z bazy wartosc lng
  6. mysql_real_escape_string($center_lng), // podana przez usera lng
  7. mysql_real_escape_string($center_lat), podana przez usera lat
  8. $wpdb->get_var("SELECT meta_value FROM wp_postmeta WHERE meta_key = 'lat'"), //brana z bazy lat
  9. mysql_real_escape_string($radius)))//podany przez usera dystans


I nie wiem jak to doprowadzić do działania. Ogólnie wydaje mi się, że błąd popełniłem przy wybieraniu wlasnie z bazy tych lat i lng natomiast nie do końca wiem jak to zrobić. Czy mógłby mi ktoś powiedzieć jak powinno wyglądać prawidłowe zapytanie?




Edit:
Tak, siedzenie po nocach nie pomaga... Tutaj powinien być jakiś INNER JOIN zamiast sprintf'a prawda? biggrin.gif
mar1aczi
Możesz wystawić zrzut kawałka tej tabeli dla 5-10 postów.
Kulfon
Mam 1 testowy post. Było ich więcej ale na moment obecny działam na jednym. Wygląda to tak:

  1. --
  2. -- Struktura tabeli dla tabeli `wp_postmeta`
  3. --
  4.  
  5. CREATE TABLE `wp_postmeta` (
  6. `meta_id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  7. `post_id` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
  8. `meta_key` varchar(255) DEFAULT NULL,
  9. `meta_value` longtext,
  10. PRIMARY KEY (`meta_id`),
  11. KEY `post_id` (`post_id`),
  12. KEY `meta_key` (`meta_key`)
  13. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  14.  
  15. --
  16. -- Zrzut danych tabeli `wp_postmeta`
  17. --
  18.  
  19. INSERT INTO `wp_postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES
  20. (411, 75, 'name', 'Miejsce 1'),
  21. (412, 75, 'address', 'Dywizjonu 303 11/505 30-123 KrakĂłw'),
  22. (420, 75, 'publicOrPrivate', 'public'),
  23. (423, 75, 'telefon', '123123123'),
  24. (426, 75, 'custom_logo', 'custom_logo_75.jpg'),
  25. (427, 75, 'custom_photo1', 'custom_photo1_75.jpg'),
  26. (428, 75, 'custom_photo2', 'custom_photo2_75.jpg'),
  27. (658, 75, 'lat', '50.08491009999999'),
  28. (659, 75, 'lng', '20.003797200000008');
mar1aczi
W jednym wierszu post_id, lat, lng i odległość (musisz podstawić do wzoru):
  1. SELECT r.post_id,
  2. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  3. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng,
  4. 'obliczenia' AS distance
  5. FROM (
  6. SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  7. GROUP BY r.post_id

Z resztą powinieneś sobie poradzić wink.gif
Kulfon
Aaa czekaj w sensie jak podstawić: "W jednym wierszu post_id, lat, lng i odległość (musisz podstawić do wzoru):".
O tyle o ile wydaje mi się, że rozumiem zapytanie to nie wiem o co Ci chodziło biggrin.gif
mar1aczi
Tam gdzie ja wstawiłem 'obliczenia' musisz zastosować wzór na odległość między punktami. Współrzędne punktu od użytkownika pobierasz przed wykonaniem zapytania i "wkładasz" do wzoru w zapytaniu z odpowiednim where/having.
Kulfon
I wyszło coś takiego:
  1. sprintf("SELECT r.post_id,
  2. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  3. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng,
  4. ( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) )
  5. AS distance HAVING distance < '%s'
  6. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  7. GROUP BY r.post_id LIMIT 0, 20",


Natomiast wynik zapytania to pusta tablica - nic mi nie zwraca :/

Dobra... to szukam błędu
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'HAVING distance < '100'
FROM (SELECT post_id, meta_key, meta_value FROM wp_postm' at line 5
mar1aczi
Podstaw wartości "od użytkownika" ręcznie do zapytania i sprawdź czy zapytanie wykona Ci się poprawnie "z palca" np. w phpmyadmin.
Kulfon
To niestety też jest błąd - dokładnie taki sam
Przykładowo zapytanie wygląda tak:
  1. SELECT r.post_id,
  2. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  3. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng,
  4. ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( lat ) ) ) )
  5. AS distance HAVING distance < 100
  6. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  7. GROUP BY r.post_id LIMIT 0, 20


Ok, delikatnie zmieniłem zapytanie:

  1. SELECT r.post_id,
  2. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  3. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng,
  4. ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( lat ) ) ) )
  5. AS distance
  6. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r HAVING distance < 100
  7. GROUP BY r.post_id LIMIT 0, 20


i teraz jeszcze:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GROUP BY r.post_id' at line 7
mar1aczi
Tak:
  1. SELECT rr.post_id, rr.lat, rr.lng,
  2. ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( rr.lat ) ) * cos( radians( rr.lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( rr.lat ) ) ) ) AS distance
  3. FROM (
  4. SELECT r.post_id,
  5. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  6. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng
  7. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  8. GROUP BY r.post_id) rr
  9. HAVING ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( rr.lat ) ) * cos( radians( rr.lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( rr.lat ) ) ) ) < 100

Poczytaj o składni zapytań sql, przyda Ci się taka lektura wink.gif
Kulfon
Tak, racja trochę zaniedbałem bazy danych wstydnis.gif

Hmm tego kodu nie można zmienić na taki? Czemu powtarzać wzór skoro mamy 'AS distance'. To poniżej również działa smile.gif

  1. SELECT rr.post_id, rr.lat, rr.lng,
  2. ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( rr.lat ) ) * cos( radians( rr.lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( rr.lat ) ) ) ) AS distance
  3. FROM (
  4. SELECT r.post_id,
  5. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  6. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng
  7. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  8. GROUP BY r.post_id) rr
  9. HAVING distance < 100


Jeszcze jedno małe pytanko. smile.gif

O tyle o ile dane z innej tabeli wyciągnę sobie dodając na koniec tego zapytania:
  1. LEFT JOIN `wp_ratings` ON (rr.post_id = `wp_ratings`.post_id)
i po pierwszym SELECT nazwa_kolumny
to zupełnie nie wiem jak dzięki temu zapytaniu z postu powyżej wyciągnąć wartość dla innego meta_key np wartość dla address - czyli żeby oprócz lat i lng jak do tej pory wypluwało również address...
mar1aczi
Np.
  1. SELECT rr.post_id, rr.lat, rr.lng,
  2. ( 3959 * acos( cos( radians(50.0952545) ) * cos( radians( rr.lat ) ) * cos( radians( rr.lng ) - radians(20.078393600000027) ) + sin( radians(50.0952545) ) * sin( radians( rr.lat ) ) ) ) AS distance, (SELECT meta_value FROM wp_postmeta p WHERE p.post_id = rr.post_id AND p.meta_key = 'address') AS address
  3. FROM (
  4. SELECT r.post_id,
  5. sum(IF(meta_key = 'lat', meta_value, 0)) AS lat,
  6. sum(IF(meta_key = 'lng', meta_value, 0)) AS lng
  7. FROM (SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key IN ('lat', 'lng')) r
  8. GROUP BY r.post_id) rr
  9. HAVING distance < 100
Kulfon
No tak, próbowałem w ten sposób:
  1. SELECT meta_value FROM wp_postmeta WHERE meta_key = 'address' AS address


Wielkie dzięki smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.