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:
SELECT h.*, count(hs.HardID) AS liczba FROM hardware AS h LEFT JOIN cthardtosoft AS hs ON (h.HardID = hs.HardID) WHERE h.HardID IS NULL OR hs.SoftID != '12' GROUP BY hs.HardID HAVING liczba <= 1
SELECT * FROM hardware WHERE HardID IN ( SELECT HardID FROM cthardtosoft WHERE SoftID != '12' GROUP BY HardID HAVING count(*) <= 1 )
hmmmm, tak teoretycznie, bez sprawdzania:
SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON (HS.HardID=H.HardID AND HS.SoftID=12) WHERE HS.HardID IS NULL
@nospor - dzieki, dziala ... nie ma to jak uczucie ze wkoncu sie udalo po dluzszym czasie meczenia sie
@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 a wiec przezucmy ze zloczenia do where:
SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL AND 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).
SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL OR HS.SoftID!=12
Zaraz zaraz a co z:
SELECT * FROM hardware H LEFT JOIN cthardtosoft HS ON HS.HardID=H.HardID WHERE HS.HardID IS NULL AND HS.SoftID!=12
@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
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ąć
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.
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)