Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Relacja wiele do wileu w jednym rekordzie
Forum PHP.pl > Forum > Bazy danych > MySQL
Siner
Witam,
mam 3 tabele, news, categories, news_to_categories. Chciałem pobrać news i kategorie dla danego wpisu w taki sposób:
  1. SELECT *
  2. FROM `a_news` n
  3. LEFT JOIN a_news_to_categories nc ON n.id = nc.newsID
  4. LEFT JOIN a_categories c ON c.id = nc.categoryId

Tylko w przypadku gdy do news przypisane są 3 kategorie to są zwracane mi 3 rekordy z takimi samymi kolumnami tylko innymi kategoriami. Czy da się stworzyć takie zapytanie żeby wszystko było zwrócone w jednym rekordzie?
ayeo
Użyj podzapytania i IN
MMPrime
Najwygodniej będzie podzielenie tego na dwa zapytania. Pierwszym pobierasz newsy, potem w pętli wyodrębniasz id newsów. Następnie tworzysz zapytanie pobierające kategorie dla tych postów.

Rozwiązanie to jest bardzo wygodne, dodatkowo nie obciąża też serwera.
Siner
Cytat(ayeo @ 27.04.2008, 21:58:56 ) *
Użyj podzapytania i IN
A możesz na przykładzie pokazać jak to zrobić. Kombinuje ale nie wychodzi mi za bardzo.
  1. SELECT *
  2. FROM `a_news` n
  3. LEFT JOIN a_news_to_categories nc ON n.id = nc.newsID
  4. IN (
  5.  
  6. SELECT c.title
  7. FROM a_categories c
  8. WHERE c.id = nc.categoryId
  9. )

Przy takim zapytaniu otrzymuje dodatkowo pola z news_to_categories z wartością NULL.



Cytat(MMPrime @ 27.04.2008, 22:02:27 ) *
Najwygodniej będzie podzielenie tego na dwa zapytania. Pierwszym pobierasz newsy, potem w pętli wyodrębniasz id newsów. Następnie tworzysz zapytanie pobierające kategorie dla tych postów.
Rozwiązanie to jest bardzo wygodne, dodatkowo nie obciąża też serwera.
Nie rozumiem, mam dać zapytania w pętli? Raczej takie coś nie będzie optymalne dla serwera.
MMPrime
Najpierw pobierasz wszystkie newsy, wyodrębniasz id tych newsów w pętli. Następnie poza pętla budujesz zapytanie SQL z wyodrębnionych danych.
ayeo
Pokaż strukturę swoich tabel to Ci napiszę jedno zapytanie co to załatwi

edit:
Coś takiego:
  1. SELECT
  2. n.title,
  3. c.name
  4. FROM news n,
  5. categories c
  6. WHERE n.id = $id AND c.id IN (
  7. SELECT
  8. cat_id
  9. FROM news2categories WHERE news_id = $id )
Sedziwoj
(miałem coś skomentować, ale sobie daruję)

Co do problemu Siner, to niestety ale wiersz by musiał nie być rekordem, a obiektem... Chyba że się robi inne triki, ale to tylko w szczególnych przypadkach.
Np. jak do News'a potrzebujesz string'a z nazwami kategorii oddzielonymi przecinkami, bo da się to zrobić jednym zapytaniem, ale jak potrzebujesz wszystkich danych to jest już problem, bo nie da się tego "ładnie" zrobić. (ORM to robi, ale to dla każdego News'a pobiera jego kategorie, więc jest n+1 zapytań do bazy (n - liczba news'ów)

P.S. Przeczytałem jeszcze raz pierwszego posta w temacie, więc moim zdaniem użyć 2 kwerend...
Siner
Dobra trochę zwątpiłem w swoje możliwości. Mógłby ktoś mi podać przykładowe zapytania. Aby pobrać wpisy(np newsy) i aby do każdego był przypisane kategorie do których należy.
Przykładowa struktura tabel:
Kod
News:
-id
-title
-text

Categories
-id
-title

News_to_Categories
-newsId
-categoryId


Z góry dzięki.
phpion
Możesz to zrobić na jednym zapytaniu. Kategorie zostaną zwrócone w formie nazw oddzielonych np. przecinkiem. Możesz również prócz nazwy kategorii wybrać jej id (tworzysz wtedy ciag np. id1:nazwa1|id2:nazwa2|id3:nazwa3). Czego użyć? GROUP_CONCAT
Siner
No dobra udało mi się, powstało mi już jakieś ciekawsze zapytanie. Ale spotkałem jeszcze jeden problem.
  1. SELECT a_news. * ,
  2. GROUP_CONCAT( a_categories.title SEPARATOR ', ' ) AS kategorie,
  3. GROUP_CONCAT( a_categories.url SEPARATOR ', ' ) AS urle,
  4. a_users.login FROM a_news LEFT JOIN a_news_to_categories ON ( a_news.id = a_news_to_categories.newsId )
  5. LEFT JOIN a_categories ON ( a_news_to_categories.categoryId = a_categories.id )
  6. LEFT JOIN a_users ON ( a_users.id = a_news.author )
  7. WHERE a_news.SHOW = 1 AND a_categories.url = '$category'
  8. GROUP BY a_news.id
  9. LIMIT $page, $perPage

Gdy chcę pobrać wpisy tylko z konkretnej kategorii "WHERE a_news.show = 1 AND a_categories.url = '$category'" w kolumnie gdzie powinienem mieć zgrupowane wszystkie kategorie newsa, a mam tylko i wyłącznie tą jedna dopasowaną do warunku z WHERE, czy da się jakoś zrobić żeby ten warunek nie rzutował na wynik join-ów lub group?
woj_tas
Spróbuj tak:
  1. SELECT a_news. * ,
  2. GROUP_CONCAT( a_categories.title SEPARATOR ', ' ) AS kategorie,
  3. GROUP_CONCAT( a_categories.url SEPARATOR ', ' ) AS urle,
  4. a_users.login FROM a_news LEFT JOIN a_news_to_categories ON ( a_news.id = a_news_to_categories.newsId )
  5. LEFT JOIN a_categories ON ( a_news_to_categories.categoryId = a_categories.id )
  6. LEFT JOIN a_users ON ( a_users.id = a_news.author )
  7. WHERE a_news.id IN (SELECT newsId FROM a_news_to_categories WHERE categoryId = '$category') AND a_news.SHOW = 1
  8. GROUP BY a_news.id
  9. LIMIT $page, $perPage


Przy czym $category to nie url tylko id kategorii.
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.