Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Złożone zapytanie do 3 tabel.
Forum PHP.pl > Forum > Bazy danych > MySQL
emjot27
Witam ma dość (jak dla mnie) skomplikowane zapytanie. Mam następujące tabelki
dokumenty, kontrahenci i bufor. W tabelce dokumenty jest odwołanie do tabelki kontrahenci po id danego kontrahenta. Po za tym w tabelce dokumenty jest Boolenowskie pole bufor mówiące o tym czy dokument jest buforze czy też nie. Jeżeli jest w buforze, to w tabelce bufor jest odpowiedni zapis z odwołaniem do tabelki dokumenty z jego id. Dodatkowo, w bazie bufor jest pole status typu enum o wartościach 'nowy' lub 'edycja' lub 'wolny'.
Teraz jak zrobić zapytanie tak, aby wybrać z bazy dokumentów dane razem z danymi kontrahenta ale tylko te rekordy które nie są nowe czyli posiadają zapis w bazie bufor, z polem status!='nowy'
Próbowałem zrobić coś takiego, ale gdzieś pewnie robie błąd:

  1. "SELECT * FROM `dokumenty` AS d, `kontrahenci` AS k, `bufor` AS b WHERE d.kontr_wchodz = k.idkontrahenci AND d.numer_wchodz LIKE '%".$dok_nr1."%' AND d.data_wplyw_wchodz LIKE '%".$dok_dat1."%' AND d.data_nad_wchodz LIKE '%".$dok_dat2."%' AND k.nazwa_kontr LIKE '%".$dok_kontr."%' AND CASE WHEN (b.id_buf_dok = d.idwchodzaca AND d.bufor = 'tak' AND b.stan_buf_dok != 'nowy' ) THEN 'true' END"


Właśnie w tym CASE czuję największą szanse...ale czy tak można robić zapytanie... Nigdy nie stosowałem takiego zapytania, ale teraz czuje, że tylko to może mi pomóc, tylko nie bardzo wiem jak to razem wszystko ładnie połączyć.

Bardzo proszę o pomoc.
Pozdrawiam.
rygiel
Proponuje zapoznać sie z łączeniem tabel za pomącą polecenia JOIN
Wtedy można uchwicić powiązane rekordy po id i po statusach.
emjot27
Dzięki.
Niestety kombinuje jak koń pod gorę, ale coś mi nie wychodzi, nie mogę za bardzo wyobrazić sobie JOINa w zastosowaniu w moim przypadku. Probowałem z różnymi przykładami występującymi na tym forum, ale nie mogę tego zgrać z moim. Czy mógłbyś mi chociaż zapisać jakiś "szkic" takiego zapytania. Czy to by było coś w tym stylu?
-----------------------------

Ok. Poradziłem sobie. Zrobiłem to tak:
  1. "SELECT * FROM dokumenty d LEFT JOIN `bufor` b ON d.iddok = b.id_buf_dok AND b.status!='nowy' AND b.status!='wolny', kontrahenci k WHERE d.kontr = k.idkontrahenci [...]"


Jednak nie działa tak jak powinno sad.gif
Wyświetlają się wszystkie dokumenty, które nie mają w ogóle wpisu w bazie bufor a powinny się wyświetlać równeż te, które mają w buforze status "edycja" sad.gif Co zmienić, żeby zadziałało ?
rygiel
Uwaga! zapytania są schematyczne nie muszą działac po wklejeniu do kodu smile.gif

Wersja nr 1

SELECT
...
FROM
dokumenty d
JOIN bufor b ON d.iddok = b.id_buf_dok
JOIN kontrahenci k ON cośtam cośtam
WHERE
b.status!='nowy'

To zapytanie zwróci wszystkie rekordy ze statusem "nowy" które mają połaczenie między tabelami dokumenty, bufor, kontrachenici


SELECT
...
FROM
dokumenty d
LEFT JOIN bufor b ON d.iddok = b.id_buf_dok
JOIN kontrahenci k ON cośtam cośtam
WHERE
b.status!='nowy'
To zapytanie zwróci to samo. LEFT JOIN używamy tylko wtedy gdy chcemy salic tabelkę z rekordami do których nie ma dowiązań. Jeśli wywali tu to co jest w WHERE to zwróci Ci wszystkie dokumenty te co sa w buforze i i ich nie ma w buforze.
---
Zauważyłem że dziwnie połączyłeś w nowym zapytaniu dałeś JOIN a puźniej przecinek następne pole.
Chyba źle też łączysz pola JOIN lepiej łącz id_z_tabeli1 = id_z_tabeli2 a warunek daj w WHERE

Moim zdaniem lepiej odzwyczaić sie łączenia tabel bez JOIN smile.gif


http://dev.mysql.com/doc/refman/5.1/en/join.html
emjot27
Ok. Zaraz "potrenuje" to, ale już na początku się zapytam, czy takie rozwiązanie będzie działało u mnie gdy w bazie bufor nie będzie żadnego rekordu odpowiadającego bazie dokumenty?
Zrobiłem tak, żeby nie przechowywać rekordów w buforze, których dokumenty nie są w danej chwili wykorzystywane i po prostu są one usuwane z bazy bufora, żeby nie zaśmiecać bazy.
rygiel
Jeśli dasz LEFT JOIN to będzie działo
emjot27
Cytat(rygiel @ 19.12.2007, 13:37:26 ) *
Zauważyłem że dziwnie połączyłeś w nowym zapytaniu dałeś JOIN a puźniej przecinek następne pole.
Chyba źle też łączysz pola JOIN lepiej łącz id_z_tabeli1 = id_z_tabeli2 a warunek daj w WHERE

Hmm...no właśnie, ale coś mi nie wychodzi z tym joinem gdy go próbuje wywołać drugi raz łącząc tabele dokumenty z kontrahentami.
mam tak: (schematycznie)
  1. "SELECT * FROM dokumenty d LEFT JOIN bufor b ON d.iddok= b.id_bufor JOIN kontrahenci k ON d.kontr = k.idkontrahenci WHERE b.status!='nowy'"

Wywala mi błąd:
Something is wrong in your syntax obok 'ON d.kontr = k.idkontrahenci WHERE b.status!='nowy'' w linii 1

Ufffff udało się winksmiley.jpg
w powyższym kodzie musiałem również użyć LEFT JOIN aby połączyć tabele kontrahentów i dokumentów ale to nadal nie rozwiązywało sprawę, bo pokazywały mi się tylko te rekordy dokumentów, które mają swe zapisy w buforze. Musiałem pokombinować z warunkami i UDAŁO SIĘ biggrin.gif
o to co mi wyszło...
  1. "SELECT * FROM dokumenty d LEFT JOIN bufor b ON d.iddok= b.id_bufor LEFT JOIN kontrahenci k ON d.kontr = k.idkontrahenci WHERE (d.bufor='nie' OR (b.status!='nowy' AND b.status!='wolny'))"


Ogólnie strasznie dla mnie to zakręcone - ale ważne, ze działa. Mam tylko, nadzieje, że w trakcie "prania" nie wyjdą z tego jakieś "krzaczki"
Póki co, to dzięki za pomoc. - cały dzionek przez to zmarnowałem :/
rygiel
nie wiem czy ten błąd nie tyczy się mysql 4.x ablo niższego. W domu lokalny kompku mam podobnie z JOIN'ami.

Grunt że się udało smile.gif Warto sie z tym oswoić daje duże możliwości.

Pozdrawiam
Indeo
Jeśli każdy dokument jaki Cię interesuje musi istnieć w buforze wystarczy całe zapytanie zacząć od ....

bufora... i odpada cała zabawa z złożonym warunkiem
  1. SELECT * FROM bufor B INNER JOIN dokumenty D ON B.id_bufor=D.iddok
  2. INNER JOIN kontrahenci K ON D.kontr=K.idkontrahenci
  3. WHERE B.STATUS <>'nowy'


I jeszcze jedna uwaga. Słowo status jest słowem kluczowym mysql i nie nalezy go używać bez odwrotnych apostrofów!
emjot27
Witam.
Dzięki za zainteresowanie tematem.
Na początku musze stwierdzić, że jednak moje ostatnie rozwiązanie nie dzialało w pełni dobrze, gdyż w momencie wyszukiwania wg jakichkolwiek danych kontrahenta np miejscowości albo nazwie, pojawiały się takie "krzaczki", że wyświetlał i tak wszystkie rekordy jakie istnieją w bazie dokumenty a tam gdzie (np wyszukiwałem miasto Łódź) było takie miasto, pojawiała się nazwa a w pozostałych było pusto. Pomogło zmiana tego zapytania na taką formę:
  1. "SELECT * FROM `dokumenty` d LEFT JOIN `bufor_dok` b ON d.iddok = b.id_buf_dok, `kontrahenci` AS k WHERE d.kontr = k.idkontrahenci AND itd[...]"

Teraz wszystko działa super, ale pewnie wg was nie jest to "ładnie" wg składni ?
Cytat(Indeo @ 19.12.2007, 22:44:40 ) *
Jeśli każdy dokument jaki Cię interesuje musi istnieć w buforze wystarczy całe zapytanie zacząć od ....
bufora... i odpada cała zabawa z złożonym warunkiem

U mnie z tym buforem jest trochę zakręcone, gdyż:
- jest sobie baza dokumentów, która oprócz podstawowych pól tj id i dane posiada pole bufor typu Enum, które może przyjmować wartości [tak/nie]
- jest baza bufor, która posiada swoje id i id dokumentu którego dotyczy rekord a także pole status_bufor typu ENUM które może przyjąć 3 wartości [nowy/edycja/wolny]
Teraz działa to tak.
Jeśli jest wprowadzany nowy dokument zostaje wygenerowany pusty rekord w bazie dokumentów i zapisana jedynie komórka w polu bufor na [tak]. pole id generuje się automatem jako kolejny numer id dokumentu. Jednocześnie w bazie bufor tworzy się nowy rekord gdzie linkuje się id dokumentu i nadaje polu status_bufor wartośc: 'nowy'.
Jeśli ktoś, wyjdzie i nie zapisze tego dokumentu, to jedynie w bazie bufor zmieni się status_bufor wartość na 'wolny'.
Jeśli jednak ktoś go zapiszę, to rekord w bazie bufor zostanie usunięty, a w bazie dokumenty pole bufor zmieni się na 'nie'. Jeżeli ktoś zechce edytować ten dokument to stworzy się nowy rekord w buforze o status_bufor = 'edycja' a w dokumentach w polu bufor znowu na 'tak'.

Trochę to poplątane, ale działa jak na razie świetnie, dlatego też wyszukiwanie musiało uwzględniać możliwość nie istnienia rekordów w bazie bufor. To moje ostatnie zapytanie działa teraz wyśmienicie.
Cytat(Indeo @ 19.12.2007, 22:44:40 ) *
I jeszcze jedna uwaga. Słowo status jest słowem kluczowym mysql i nie nalezy go używać bez odwrotnych apostrofów!

Spokojnie, wiem o tym, tutaj na forum zastosowałem zapis schematyczny, gdyż w rzeczywistości w programie stosuję zupełnie inne nazewnictwo, np wspominany status to u mnie `status_bufor`.
Pozdrawiam i dziękuję za radę.
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.