Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Limitowanie wyników przy łączeniu tabel
Forum PHP.pl > Forum > Bazy danych
starach
Witam.
Spotkałem się z problemem stronicowania przy łączeniu kilku tabel.
Załóżmy że mam tabelę artykułów, ich kategorii i trzecią w której składuje identyfikatory artykułów i kategorii celem powiązania ich ze sobą.
W zapytaniu łączę tabele ( LEFT JOIN ) co w przypadku dwóch kategorii przypisanych do jednego artykułu zwróci mi dwa wyniki opisujące jeden artykuł.
Co mam zrobić w takim razie jeśli chcę pobrać tylko 5 artykułów? Jeśli wpiszę LIMIT 5 artykuł z dwiema kategoriami zwróci mi dwa wiersze wyników i tak na prawdę tylko 4 artykuły zostaną pobrane.
Czy można wprowadzić limit na kolumnę ? Na przykład: Pobierz dane z tabeli artykuły łącząc z tabelą łącznik gdzie art.id = łącznik.art_id i połącz z kategorie gdzie cat.id = łącznik.cat_id WHERE art.id 5 unikalnych - zamiast LIMIT 5

edit>
Moje wyjaśnienie pewnie guzik daje więc wrzucam bazę i zapytanie
  1. /*Table structure for table `article_categories` */
  2.  
  3. CREATE TABLE `article_categories` (
  4. `acs_id` int(11) NOT NULL AUTO_INCREMENT,
  5. `acs_name` varchar(256) DEFAULT NULL,
  6. `acs_color` varchar(9) DEFAULT NULL,
  7. PRIMARY KEY (`acs_id`)
  8. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
  9.  
  10. /*Data for the table `article_categories` */
  11.  
  12. INSERT INTO `article_categories`(`acs_id`,`acs_name`,`acs_color`) VALUES (1,'Test 1','00ff00'),(2,'Test 2','00ff00'),(3,'Test 3','00ff00');
  13.  
  14. /*Table structure for table `article_category` */
  15.  
  16. CREATE TABLE `article_category` (
  17. `_al_id` int(11) NOT NULL,
  18. `_acs_id` int(11) NOT NULL
  19. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  20.  
  21. /*Data for the table `article_category` */
  22.  
  23. INSERT INTO `article_category`(`_al_id`,`_acs_id`) VALUES (1,1),(1,2),(2,1),(2,2),(2,1),(3,1),(3,3),(4,1),(4,4);
  24.  
  25. /*Table structure for table `article_list` */
  26.  
  27. CREATE TABLE `article_list` (
  28. `al_id` int(11) NOT NULL AUTO_INCREMENT,
  29. `al_title` varchar(256) NOT NULL,
  30. `al_desc` text NOT NULL,
  31. `al_content` text NOT NULL,
  32. `al_date_added` datetime NOT NULL,
  33. `al_date_update` datetime NOT NULL,
  34. `_u_id` int(11) NOT NULL,
  35. PRIMARY KEY (`al_id`)
  36. ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
  37.  
  38. /*Data for the table `article_list` */
  39.  
  40. INSERT INTO `article_list`(`al_id`,`al_title`,`al_desc`,`al_content`,`al_date_added`,`al_date_update`,`_u_id`) VALUES (1,'Tytul 1','Opis 1','Treść 1','0000-00-00 00:00:00','0000-00-00 00:00:00',1),(2,'Tytul 2','Opis 2','Treść 2','0000-00-00 00:00:00','0000-00-00 00:00:00',1),(3,'Tytuł 3','Opis 3','Treść 3','0000-00-00 00:00:00','0000-00-00 00:00:00',1),(4,'Tytuł 4','Opis 4','Treść 4','0000-00-00 00:00:00','0000-00-00 00:00:00',1),(5,'Tytuł 5','Opis 5','Treść 5','0000-00-00 00:00:00','0000-00-00 00:00:00',1),(6,'Tytuł 6','Opis 6','Treść 6','0000-00-00 00:00:00','0000-00-00 00:00:00',1);
Zapytanie:
  1. SELECT `al`.`al_id`, `al`.`al_title`, `al`.`al_desc`,
  2. `al`.`al_date_added`, `al`.`al_date_update`, `al`.`_u_id`, `ac`.*, `acs`.*
  3. FROM `article_list` AS `al`
  4. LEFT JOIN `article_category` AS `ac` ON `al`.`al_id` = `ac`.`_al_id`
  5. LEFT JOIN `article_categories` AS `acs` ON `acs`.`acs_id` = `ac`.`_acs_id` LIMIT 5

Dostanę wynik:
Cytat
+-------+----------+---------+-
| al_id | al_title | al_desc |
+-------+----------+---------+-
| 1 | Tytul 1 | Opis 1 |
| 1 | Tytul 1 | Opis 1 |
| 2 | Tytul 2 | Opis 2 |
| 2 | Tytul 2 | Opis 2 |
| 3 | Tytul 3 | Opis 3 |
+-------+----------+---------+-
Czyli zamiast 5 wyników dostaję 3 wyniki. Winowajcą jest LIMIT który zlicza mi wiersze zamiast unikalnych wystąpień na przykład al_id. Jak zmusić zapytanie do pobierania wyników o 5 unikalnych identyfikatorach a nie 5 wierszach.
Mati7
Można użyć GROUP BY, ale nie wiem czy takie zapytanie będzie zwracało to o ci chodzi.

  1. SELECT `al`.`al_id`, `al`.`al_title`, `al`.`al_desc`,
  2. `al`.`al_date_added`, `al`.`al_date_update`, `al`.`_u_id`, `ac`.*, `acs`.*
  3. FROM `article_list` AS `al`
  4. LEFT JOIN `article_category` AS `ac` ON `al`.`al_id` = `ac`.`_al_id`
  5. LEFT JOIN `article_categories` AS `acs` ON `acs`.`acs_id` = `ac`.`_acs_id` GROUP BY `al`.`al_id` LIMIT 5
starach
No właśnie niestety nie zwraca. Łączy wyniki według al_id i ilość wyników jest poprawna.
Niestety przy okazji również kasuje wyniki kategorii. Czyli do każdego artykułu jest dopisana jedna kategoria,
a nie 3, 2 bądź ileś tam.
Mati7
Hm nie wiem czy da się to zrobić za pomocą jednego zapytania (wydaje mi się że nie).

Ja bym dopisał jedno zapytanie które pobiera powiedzmy 5 artykułów z tabeli article_list - wyświetlasz artykuły
i dla każdego arta pobierasz kategorie do których nalezy (drugie zapytanie)

czyli dla 5 artykułów miałbyś dodatkowe 5 zapytań

jeśli chodzi o wydajność to zawsze można użyć cacha...
nevt
coś w stylu:
  1. SELECT * FROM (SELECT * FROM `article_list` LIMIT 5) AS `al`LEFT JOIN `article_category` AS `ac` ON `al`.`al_id` = `ac`.`_al_id`LEFT JOIN `article_categories` AS `acs` ON `acs`.`acs_id` = `ac`.`_acs_id`;

powodzenia.
starach
Niech ci bozia w dzieciach wynagrodzi dobry człowieku.
Właśnie zamierzałem pokombinować z zagnieżdżaniem zapytań.

edit>
Zaczynam się interesować Propel'em i tak się zastanawiam jakby to mogło w nim wyglądać.
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.