Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Relacja wiele do wielu - wyciąganie danych
Forum PHP.pl > Forum > Bazy danych > MySQL
Sierak
Walcze z tym od wczoraj i pomyslalem ze moze wy mnie nakierujecie na rozwiazanie. Chodzi o odpowiednie wyciagniecie danych z tabeli ktora jest relacja wiele do wielu dla dwoch innych tabel.

Wyglada to mniej wiecej tak w duzym skrocie:
tabela: hardware
HardID 1
HardID 2
HardID 3

tabela: software
SoftID 10
SoftID 11
SoftID 12

tabele: cthardtosoft
HardID 1; SoftID 10
HardID 1; SoftID 11
HardID 1; SoftID 12
HardID 2; SoftID 10
HardID 2; SoftID 11
HardID 3; SoftID 10

Zapytanie w postaci listy wszystkich komputerow ktore POSIADAJA jakis soft to prosta sprawa. Ale mam klopot z odwrotna sytujacja. Chce liste komputerow ktore np. NIE POSIADAJA softu o ID 12

Probowalem w taki sposob ale mam przeklamane dane:
  1. SELECT h.*, count(hs.HardID) AS liczba
  2. FROM hardware AS h
  3. LEFT JOIN cthardtosoft AS hs ON (h.HardID = hs.HardID)
  4. WHERE h.HardID IS NULL OR hs.SoftID != '12' GROUP BY hs.HardID HAVING liczba <= 1


lub tak:
  1. SELECT * FROM hardware WHERE HardID
  2. IN (
  3. SELECT HardID FROM cthardtosoft WHERE SoftID != '12' GROUP BY HardID HAVING count(*) <= 1
  4. )


Jezeli mam wybierac to wolalbym jedno zapytanie, bez podzapytan.
Mam do dyspozycji MySQL 4.1
nospor
hmmmm, tak teoretycznie, bez sprawdzania:
  1. SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON (HS.HardID=H.HardID AND HS.SoftID=12) WHERE HS.HardID IS NULL


ps: i niech cie nie zmyli ten warunek: HS.SoftID=12. tak ma byc smile.gif
Sierak
@nospor - dzieki, dziala ... nie ma to jak uczucie ze wkoncu sie udalo po dluzszym czasie meczenia sie smile.gif

@mike_mech - skasowales swojego posta ale odpisze ... chce w jednym zapytaniu ze wzgledu na zlozonosc zapytania i dosc duza ilosc warunkow ktore uwzgledniam w wyszukiwarce.

---
No właśnie tak pomyślałem że można prościej, dlatego wywaliłem posta, bo nie wnosił do wątku dużo.
~mike_mech
bendi
Cytat(nospor @ 22.06.2006, 09:27 ) *
ps: i niech cie nie zmyli ten warunek: HS.SoftID=12. tak ma byc smile.gif


Mam takie pytanie w stylu "a dlaczego tak?" smile.gif

Wiem, że to działa i wiem, że jest poprawne, ale moje pytanie jest trochę innej natury. Chodzi o umieszczenie tego warunku przy złączeniu. Otóż ten sam waunek możemy dołożyć do części WHERE i też będzie działało. Jaka jest różnica. Czy dodanie do warunku na złączenie zapobiega dorzuceniu do macierzy rekordów nie spełniających tego warunku a wrzucenie na w WHERE spowodowałoby przemielenie wszystkich wyników i dopiero późniejsze wyciągnięcie tego co trzeba?
nospor
@bendi a wiec przezucmy ze zloczenia do where:
  1. SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL AND HS.SoftID=12

no chyba cos nie tak winksmiley.jpg oba warunki w where sie wykluczaja nawzajem. pozatym ma byc rozne od 12
no to kombinujmy dalej:
  1. SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL OR HS.SoftID!=12
no teraz tez nie za dobrze, gdyz to zapytanie zwroci nam wsyzstkie z HardID z przykladu czyli: 1,2,3. Kazdy z nich ma taki rekord, ze SoftID!=12. na dodatek te rekordy beda sie powtarzac (trzeba by wiec dac distinct).
Tak wiec nie chodzi tu o zapobieganie niepotrzebnemu ladownaiu danych, ale chodzi o poprawnosc otrzymanych wynikow. Pobieranie w zlaczeniu rekordow, ktore zawierają id=12 da nam na wyjsciu rekordy ktore ten soft zawierają i te ktore go nie zawierają. a ze nas interesują tylko te ktore nie zawierają, wiec wystraczy juz tylko where dopisac
bendi
Zaraz zaraz a co z:
  1. SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL AND HS.SoftID!=12
nospor
@bendi ale przeciez ci pisalem, ze warunek HS.HardID is null AND HS.SoftID!=12 sie wyklucza nawzajem. Wszakze u mnie bylo: HS.HardID is null AND HS.SoftID=12
ale to bez znaczenia. jak jednoczensnie HS.HardID moze byc nullem i HS.SoftID moze miec jakas wartosc? Przeciez oba te pola są z tej samej tabeli. z tego samego rekordu. i jesli HS.HardID is null to znaczy, ze nie dolaczyl zadnego rekordu i tym samym HS.SoftID tez jest null.
O, czyli wogole poprawka. akurat twoj warunek sie nawzajem nie wyklucza tylko jest jednoznaczny, czyli skoro HS.HardID is null to i HS.SoftID is null czyli autoamtycznie HS.SoftID !=12. czyli twoj warunek mozna zapisac:
where HS.HardID is null
a co w rezultacie da tylko takie rekordy, dla którech Hard nie posiada zadnego Soft. CZyli nie to co chcielismy smile.gif
bendi
Dobra chyba powoli zaczynam kapować, jakby co zgłoszę się jeszcze jutro, bo coś widzę, że moja dyńka potrzebuje trochę czasu coby to przemielić, jakies przykładziki trzasnąć smile.gif
Sierak
Cały problem polegał na tym, że jest to relacja wiele do wielu i jeden HardID moze zawierac wiele SoftID. Jezeli damy warunek tylko w WHERE to wyskocza nam relacje typu:

HardID 1; SoftID 10
HardID 1; SoftID 11

ktore mialy sie nie pokazac w przypadku gdy HardID zawiera SoftID = 12. Realizuja to tak jak napisal @nospor eliminujemy to.

Po prostu zlaczenie tabel nastepuje tylko w przypadku SoftID = 12 jezeli tak to mozna okreslic czym zalatwiamy sobie kwestie DISTINCT a NULL powoduje ze wyswietlaja sie tylko te komputery ktore NIE maja SoftID = 12.
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-2019 Invision Power Services, Inc.