Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Problem z LEFT OUTER JOIN + WHERE
Forum PHP.pl > Forum > Bazy danych > MySQL
phpion
Witam.
Mam takie tabele:
Kod
mysql> SELECT * FROM place;
+----+-----------+
| id | is_active |
+----+-----------+
|  1 |         1 |
|  2 |         1 |
+----+-----------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM property_place_distance;
+-------------+----------+----------+
| property_id | place_id | distance |
+-------------+----------+----------+
|           1 |        1 |       30 |
+-------------+----------+----------+
1 row in set (0.00 sec)

Dane wyciągam takim zapytaniem:
Kod
mysql> SELECT p.id, ppd.distance FROM place p LEFT OUTER JOIN property_place_distance ppd ON p.id=ppd.place_id WHERE ppd.property_id=1;
+----+----------+
| id | distance |
+----+----------+
|  1 |       30 |
+----+----------+
1 row in set (0.00 sec)

jednak chciałbym uzyskać taki raport:
Kod
+----+----------+
| id | distance |
+----+----------+
|  1 |       30 |
|  2 |     NULL |
+----+----------+

Czyli:
chciałbym wybrać wszystkie rekordy z tabeli "place" oraz dołączyć do nich dane z "property_place_distance" (na podstawie p.id=ppd.place_id) ale! tylko takie, dla których ppd.property_id=1 (lub inna wartość). Jeśli takowych nie będzie powinno w tych miejscach zwrócić NULL.
Jeśli macie jakiś pomysł to prosiłbym o pomoc.
pion
najtje
no to dopisz w klauzuli WHERE:

  1. ... OR ppd.distance IS NULL
phpion
Chyba nie do końca. Zmieniając property_id powinieniem zawsze dostawać taką samą liczbę rekordów (z różnymi wartościami distance), natomiast teraz wygląda to tak:
Kod
mysql> SELECT p.id, ppd.distance FROM place p LEFT OUTER JOIN property_place_distance ppd ON p.id=ppd.place_id WHERE ppd.property_id=1 OR ppd.distance IS NULL;
+----+----------+
| id | distance |
+----+----------+
|  1 |     NULL |
|  2 |       21 |
|  3 |      0.1 |
+----+----------+
3 rows in set (0.00 sec)

mysql> SELECT p.id, ppd.distance FROM place p LEFT OUTER JOIN property_place_distance ppd ON p.id=ppd.place_id WHERE ppd.property_id=2 OR ppd.distance IS NULL;
+----+----------+
| id | distance |
+----+----------+
|  1 |     NULL |
|  2 |       10 |
+----+----------+
2 rows in set (0.00 sec)
dymsza
Cytat(najtje @ 31.10.2007, 23:25:05 ) *
no to dopisz w klauzuli WHERE:

  1. ... OR ppd.distance IS NULL


to nie jest zły pomysł pod warunkiem ze dodasz takowy wpis do tabelki gdzie ppd.distance.

Jedna wtedy pojawią się powtarzające wpisy

+----+----------+
| id | distance |
+----+----------+
| 1 | 30 |
| 1 | NULL |
| 2 | NULL |
+----+----------+

Mozna wtedy to welminować stosując następujący myk grupe by id; i tera robi w where dodatkowy warunek jeśli count(id)=1 albo jesli count(id)=2 and not distance=null


to jest dość poglądowe stwierdzenie ale raczej good smile.gif daj znać czy dział smile.gif jak nie to może jeszcze coś wymyśle
phpion
O ile dobrze Cię zrozumiałem chodzi o to, aby do tabeli property_place_distance wpisywać dla każdego elementu property_id wszystkie wartości dotyczące place. Jeśli takowa wartość ma istnieć to wpisać jej wartość, natomiast jeśli jej nie ma to wpisać NULL. Wtedy wystarczy zwykły LEFT JOIN z warunkiem na property_id. Problemy widzę jednak dwa:
1. Niepotrzebne wpisy w tabeli.
2. W przypadku dodania nowego wpisu do tabeli place należałoby również wpisać do tabeli property_place_distance wszystkie property_id ustawiając ich wartość na NULL.
Na razie rozwiązałem to dwoma zapytaniami:
1. Wybiera wszystkie rekordy z place.
2. Wybiera rekordy z property_place_distance dla danego property_id.
Pętlą jadę po pierwszej tablicy i jeśli w drugiej jest odpowiadający rekord to wpisuję wartość; w przeciwnym wypadku nie wpisuję nic. Działa, różnica w wydajności nie sądzę by była kolosalna, tym bardziej, że rekordów nie jest za wiele. Jednak jeśli dałoby się to napisać w 1 zapytaniu to nauczyłbym się czegoś nowego smile.gif

###########################################################
EDIT:
###########################################################

Podbijam bo jednak może ktoś coś wymyśli (na pewno da się to zrobić...). Tabele mają taką zawartość:
Kod
mysql> SELECT * FROM category;
+----+-----------+
| id | is_active |
+----+-----------+
|  1 |         1 |
|  2 |         1 |
|  3 |         1 |
|  4 |         1 |
+----+-----------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM category_i18n;
+------------------+----+---------+
| name             | id | culture |
+------------------+----+---------+
| Agroturystyka    |  1 | pl_PL   |
| Bed&breakfast    |  2 | pl_PL   |
| Hotel            |  3 | pl_PL   |
| Obiekt zabytkowy |  4 | pl_PL   |
+------------------+----+---------+
4 rows in set (0.00 sec)

Wykonując zapytanie:
Kod
mysql> SELECT c.id, ci.name FROM category c LEFT OUTER JOIN category_i18n ci ON c.id=ci.id WHERE ci.culture='pl_PL' OR ci.culture IS NULL;
+----+------------------+
| id | name             |
+----+------------------+
|  1 | Agroturystyka    |
|  2 | Bed&breakfast    |
|  3 | Hotel            |
|  4 | Obiekt zabytkowy |
+----+------------------+
4 rows in set (0.00 sec)

otrzymuję to co chcę. Jednak gdy w warunku zmienię pl_PL na en_US w rezultacie nie dostanę żadnego rekordu. Jak zmienić powyższe zapytanie aby wypisywało wszystkie rekordy z tabeli category dołączając (jeśli istnieje) odpowiednie tłumaczenie lub (jeśli takowego nie ma) wpisywało wartość NULL?
Z góry dzięki za pomoc!

###########################################################
EDIT:
###########################################################

Pomoc nadeszła na mysql.com smile.gif może komuś się przyda:
Kod
SELECT c.id, ci.name FROM category c LEFT OUTER JOIN category_i18n ci ON c.id=ci.id AND (ci.culture='pl_PL' OR ci.culture IS NULL)
heaven
Nie wystarczy usunac OUTER i WHERE?
  1. SELECT p.id, ppd.distance FROM place p LEFT JOIN property_place_distance ppd ON (p.id=ppd.place_id AND ppd.distance=1)

mozliwe ze nie zrozumialem problemu smile.gif

auć. Problem juz rozwiazany sciana.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.