Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Relacja wiele do wielu - wyciąganie danych
Sierak
post 22.06.2006, 08:19:50
Post #1





Grupa: Zarejestrowani
Postów: 16
Pomógł: 0
Dołączył: 1.04.2004
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
nospor
post 22.06.2006, 08:27:21
Post #2





Grupa: Moderatorzy
Postów: 36 447
Pomógł: 6292
Dołączył: 27.12.2004




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


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
Sierak
post 22.06.2006, 08:39:53
Post #3





Grupa: Zarejestrowani
Postów: 16
Pomógł: 0
Dołączył: 1.04.2004
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


@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
Go to the top of the page
+Quote Post
bendi
post 22.06.2006, 11:44:13
Post #4





Grupa: Zarejestrowani
Postów: 401
Pomógł: 5
Dołączył: 14.09.2003
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


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?


--------------------
Go to the top of the page
+Quote Post
nospor
post 22.06.2006, 12:00:42
Post #5





Grupa: Moderatorzy
Postów: 36 447
Pomógł: 6292
Dołączył: 27.12.2004




@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


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
bendi
post 22.06.2006, 12:27:53
Post #6





Grupa: Zarejestrowani
Postów: 401
Pomógł: 5
Dołączył: 14.09.2003
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


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


--------------------
Go to the top of the page
+Quote Post
nospor
post 22.06.2006, 12:34:47
Post #7





Grupa: Moderatorzy
Postów: 36 447
Pomógł: 6292
Dołączył: 27.12.2004




@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


--------------------

"Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista
"Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer

Go to the top of the page
+Quote Post
bendi
post 22.06.2006, 12:59:47
Post #8





Grupa: Zarejestrowani
Postów: 401
Pomógł: 5
Dołączył: 14.09.2003
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


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


--------------------
Go to the top of the page
+Quote Post
Sierak
post 22.06.2006, 14:10:40
Post #9





Grupa: Zarejestrowani
Postów: 16
Pomógł: 0
Dołączył: 1.04.2004
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


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.

Ten post edytował Sierak 22.06.2006, 14:18:59
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 20.04.2024 - 04:06