Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL] Pobranie z jednej tabeli rekordow ktore nie sa w zaleznosciach w drugiej jednym zapytaniem
Forum PHP.pl > Forum > Przedszkole
Octobus
Przepraszam za niezrozumiały temat ale brakowalo mi słów. Otóż:
mam tabelę A => `ID`, `nazwa_towaru`
oraz tabele B => `ID`, `id_towaru`, `id_uzytkownika`

Tabela A to zwykle produkty a B to zestawienie ktory uzytkownik zamowil jakie produkty.

Chce sprytnie pobrać jednym zapytaniem rekordy z tabeli A (produkty) ktore nie kupil klient o okreslonym id, czyli co jeszcze moze kupic z calej gamy.
Pomijamy sens takiego rozwiązania, to tylko przykład.
adbacz
Jednym zapytaniem to chyba jest awykonalne aczkolwiek nie wiem czy w grę wchodzi łączenie tabel jakimś JOINem.

Można zawsze dwoma pytaniami. W jednym pobierasz wszystkie produkty, które user zamówił, a w drugim pobierasz wszystkie produkty, oprócz tych, które zostały pobrane za pomocą pierwszego zapytania. Tak będzie wg mnie najprościej, najwygodniej i najlepiej ale ja się mało znam więc zaczekaj na jakiegoś "starszaka" zaznajomionego z zapytaniami DB.

PS. Może napisz Nam do czego będzie Ci potrzebne takie złożone zapytanie albo dlaczego akurat potrzebujesz jednego zapytania do bazy, skoro można prościej dwoma. Proste rozwiązania czasem są najlepsze a poza tym, napsiałeś, że to tylko przykład. Może jakbyśmy znali prawdziwy powód dla którego chcesz wykonać to jednym zapytaniem to byśmy w tedy pomyśleli nad rozwiązaniem tego problemu.
tolomei
Przeanalizuj ten przykład:
  1. CREATE TABLE `produkty` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `nazwa` text NOT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  6.  
  7. INSERT INTO `produkty` (`id`, `nazwa`) VALUES
  8. (1, 'mysz'),
  9. (2, 'klawiatura'),
  10. (3, 'monitor'),
  11. (4, 'głośniki');
  12.  
  13. CREATE TABLE `wybrane` (
  14. `id` int(11) NOT NULL AUTO_INCREMENT,
  15. `id_produkty` int(11) NOT NULL,
  16. `user` int(11) NOT NULL,
  17. PRIMARY KEY (`id`)
  18. ) ENGINE=MyISAM DEFAULT CHARSET=utf32;
  19.  
  20. INSERT INTO `wybrane` (`id`, `id_produkty`, `user`) VALUES
  21. (1, 2, 2),
  22. (2, 3, 2);
  23.  
  24. SELECT id FROM produkty
  25. WHERE NOT EXISTS
  26. (
  27. SELECT id_produkty
  28. FROM wybrane
  29. WHERE produkty.id = wybrane.id_produkty
  30. AND wybrane.user =2
  31. );


Zwraca id wszystkich niewybranych produktów użytkownika 2.
Octobus
Ok znalazłem bardzo fajny sposób, nie wiedziałem że tak można


Kod
SELECT `A`.`ID` , `A`.`nazwa_towaru`
FROM `A` , `B`
WHERE `A`.`ID` = `B`.`id_towaru`
AND `B`.`id_uzytkownika` =2


Działa super biggrin.gif
phpion
Hmmm, a czy to przypadkiem nie zadziała w drugą stronę, tj. wybierze produkty, które kupił użytkownik? Rozwiązaniem problemu będzie rozwiązanie zasugerowane przez ~tolomei, albo wykonanie LEFT JOIN i wybranie produktów, które mają wartość NULL przy złączeniu.
Octobus
masz racje, o tej godzinie chyba jeszcze nie mysle ...

wartosc null ? w sumie mozna ale to trzeba dodatkowo w php obrabiac, chce to zrobic jak najkrócej. Chyba zrobie tak jak prawi @tolomei dzięki za rady
mortus
Problem można rozwiązać na trzy sposoby, pierwszy podał tolomei (użycie NOT EXISTS):
  1. SELECT `p`.`id` FROM `produkty` `p` WHERE NOT EXISTS (SELECT `w`.`id_produkty` FROM `wybrane` `w` WHERE `p`.`id` = `w`.`id_produkty` AND `w`.`user` = 2);

Drugi sposób to ten, o którym wspomniał phpion (zastosowanie LEFT JOIN / IS NULL):
  1. SELECT `p`.`id`, `p`.`nazwa` FROM `produkty` `p` LEFT JOIN `wybrane` `w` ON (`w`.`id_produkty` = `p`.`id` AND `w`.`user` = 2) WHERE `w`.`id` IS NULL

Można jeszcze użyć NOT IN:
  1. SELECT `p`.`id`, `p`.`nazwa` FROM `produkty` `p` WHERE `p`.`id` NOT IN (SELECT `w`.`id_produkty` FROM `wybrane` `w` WHERE `w`.`user` = 2)

Okazuje się, że zapytanie wykorzystujące NOT EXISTS jest najwolniejsze z tych trzech aż o ok. 30%, natomiast wydajność dwóch pozostałych zapytań jest porównywalna. Dlatego przy większej liczbie produktów radziłbym użyć albo zapytania z LEFT JOIN / IS NULL, albo zapytania z NOT IN.

Odsyłam do źródła.

EDIT
Cytat
wartosc null ? w sumie mozna ale to trzeba dodatkowo w php obrabiac, chce to zrobic jak najkrócej

Nic nie trzeba obrabiać po stronie PHP, jeśli wykorzystamy zapytanie z LEFT JOIN / IS NULL, bo te rekordy z pustą wartością nie będą uwzględnione.
Octobus
Dziękuje za przykłady, o niektórych rzeczach nie wiedziałem więc się poduczyłem dzięki wam.
Pozdrawiam
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.