Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: SELECT
Forum PHP.pl > Forum > Bazy danych > MySQL
Athlan
Ajjj... dawno nie pisałem smile.gif Więc witam smile.gif

Mój problem polega na tym, że potrzebuje wybrać dane z drugiej tabeli, jednakże LEFT JOIN tu zawodzi.

Posiadam tabele:
  1. --
  2. -- Struktura tabeli dla `notes`
  3. --
  4.  
  5. CREATE TABLE `notes` (
  6. `note_id` int(11) NOT NULL AUTO_INCREMENT,
  7. `note_blog` int(11) NOT NULL,
  8. `note_author` int(11) NOT NULL,
  9. `note_time` int(11) NOT NULL,
  10. `note_update` int(11) NOT NULL,
  11. `note_title` varchar(255) NOT NULL,
  12. `note_rewrite` varchar(255) NOT NULL,
  13. `note_text` longtext NOT NULL,
  14. `note_active` enum('y','n') NOT NULL DEFAULT 'n',
  15. `note_comments` enum('y','n') NOT NULL DEFAULT 'y',
  16. PRIMARY KEY (`note_id`),
  17. KEY `note_rewrite` (`note_rewrite`),
  18. KEY `note_blog` (`note_blog`),
  19. KEY `note_time` (`note_time`),
  20. KEY `note_author` (`note_author`),
  21. KEY `note_active` (`note_active`),
  22. KEY `note_update` (`note_update`)
  23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
  24.  
  25. -- --------------------------------------------------------
  26.  
  27. --
  28. -- Struktura tabeli dla `tags`
  29. --
  30.  
  31. CREATE TABLE `tags` (
  32. `tag_name` varchar(255) NOT NULL,
  33. `tag_note` int(11) NOT NULL,
  34. `tag_blog` int(11) NOT NULL,
  35. PRIMARY KEY (`tag_name`,`tag_note`),
  36. KEY `tag_blog` (`tag_blog`)
  37. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Przy zapytaniu:
  1. SELECT * FROM notes

chciałbym pobrać również wszystkie rekordy z tabeli tags gdzie tag_note = note_id przypisane do wybieranego rekordu.

LEFT JOIN pobierze tylko jeden tag (rekord z tabeli tags), a chciałbym otrzymać wszystkie w jednym zapytaniu. Jakieś sugestie? Dzięki za odpowiedź smile.gif

Pozdrawiam, Athlan
Norbas
Szczerze mówiąc nie wiem z czym masz problem. Zastoswanie LEFT JOIN powinno zwrócić wszystkie powiązane rekordy z tabeli 'tags' a nie tylko jeden jak piszesz. Może grupujesz wyniki zapytania? Zapytanie może wyglądać następująco:
  1. SELECT notes.*,tags.*
  2. FROM notes LEFT JOIN tags ON tags.tag_note=notes.note_id
Athlan
@Norbas, zanim coś napiszesz sprawdź czy to działa smile.gif

LEFT JOIN przypina z lewej strony (czyli dane mogą nie istnieć) TYLKO I WYŁĄCZNIE kolejne pola, nie rekordy.
RIGHT JOIN przypina pola z prawej strony, czyli nasz rekord który przpinamy z drugiej tabeli MUSI istnieć.

Pozdro smile.gif
Norbas
Dobra sprawdziłem, chociaż nigdy nie sprawdzam tak prostych zapytań winksmiley.jpg
Załóżmy, że mamy taką strukturę tabel jak podałeś. Dopisujemy dane:
  1. INSERT INTO `notes` (`note_id`) VALUES (1),(2);
  2. INSERT INTO `tags` (`tag_name`, `tag_note`) VALUES ('t1', 1), ('t2', 1), ('t2', 2);

Czyli tagi 't1' i 't2' są powiązane z pierwszą notatką, zaś 't2' z drugą.
Po wykonaniu zapytania, które podałem (z ewentualnym sortowaniem) otrzymamy (pomijam nieistotne pola z obu tabel):
Kod
note_id | tag_name
   1    |   t1
   1    |   t2
   2    |   t2

czyli moim zdaniem tak jak chciałeś:
Cytat
chciałbym pobrać również wszystkie rekordy z tabeli tags gdzie tag_note = note_id przypisane do wybieranego rekordu.

Chyba, że inaczej rozumiemy słowo rekord?
AcidBurnt
orpocz left i right sa jeszcze alter, inner join, sprawdz, ja nigdy nie pameitam ktory co robi ;]
Athlan
Norbas, misiu...

Cytat
chciałbym pobrać również wszystkie rekordy z tabeli tags gdzie tag_note = note_id przypisane do wybieranego rekordu.
Norbas
Cytat
Norbas, misiu...
Ale czułości, żebyś chociaż był kobietą winksmiley.jpg

Widzę, że dalej się nie rozumiemy. Przecież otrzymasz wszystkie powiązane rekordy z tagami.

Domyślam się co chcesz uzyskać (ale tego nie napisałeś): chcesz wyświetlić listę notatek z tagami przyporządkowanymi do danej notatki. Jeżeli tak, to można zastosować zapytanie, które podałem, ale jest w tym wypadku problem ze stronicowaniem, gdyż nie wiadomo ile tagów jest przyporządkowane do danej notatki. Moim zdaniem w takiej sytuacji jedno zapytanie nie wystarczy. W takim wypadku proponuję inne rozwiązanie.
Wykonujesz zapytanie o notatki:
  1. SELECT * FROM notes ORDER BY ...
  2. LIMIT ...

W pętli przetwarzasz wyniki zapytania wstawiając je do tablicy wyników i rezerwujesz jeden element takiej tablicy na tagi przyporządkowane do danej notatki:
Kod
$returns[$rows['note_id']] = array(
  'note_blog' => $row['note_blog'],
//  itd. (pola, które są potrzebne)
  'tags' => array()
);


Następnie mając identyfikatory notatek wykonujesz drugie zapytanie tylko o tagi dla odczytanych identyfikatorów:
Kod
'SELECT * FROM tags WHERE tag_note IN (' . impode(',', array_keys($returns)) . ')'


W kolejnej pętli dodajesz odczytane wyniki tego zapytania do odpowiedniego elementu tablicy wyników:
Kod
$returns[$row['tag_note']['tags'][] = array(
  'tag_name' => $row['tag_name'],
  'tag_blog' => $row['tag_blog']);


Jeżeli źle się domyślam, to pokaż na danych, które podałem jakie wyniki chcesz uzyskać.
Athlan
Norbas, właśnie dokładnie tak mam rozwiązane kategorie linków... no inaczej chyba się nie dało.

Chciałem się dowiedzieć, czy sam wpadłem na ten pomysł i czy się nie da tego jakoś prościej. Najwidoczniej trzeba sobie to filtrować w PHP samemu, tak jak zrobiłem to z linkami i jak podałeś wyżej.

No nic... trudno. Btw, ze stronnicowaniem nie będzie problemu smile.gif
envp
A może najprościej zrobil LEFT JOIN notes a nie tags ? smile.gif Pozdrawiam, Kamil
SongoQ
Panowie to jest jakas amatorka. LEFT JOIN przeciez to jak witaj swiecie.
Athlan
Cytat
A może najprościej zrobil LEFT JOIN notes a nie tags ? smilingsmiley.gif Pozdrawiam, Kamil

i tu może być problem z stronnicowaniem notek (dokładniej limitami), taki pomysł też miałem, bo duble notes można łatwo usunąć. Może nie tyle problem, bo to też się da. Ale jak przypisujemy po 7 - 12 tagów na notkę, to mnie się wydaje że to nie będzie wydajne.

Cytat
Panowie to jest jakas amatorka. LEFT JOIN przeciez to jak witaj swiecie.

Coś sugerujesz? snitch.gif Jakaś recepta na problem?

Póki co mamy 3 pomysły:
- przelecieć foreachem i dokonać kolejne zapytania osobno na każdą notkę, czyli na każdą notkę osobne zapytanie o tagi (najgorsze, ale jak będzie cache to nie wiem...)
- zaznaczyć tagi i joinować notki (tak jak to przedstawił Kamil)
- wykonać 2 zapytania: o notki, a następnie o tagi z wyróżnieniem ID notek, które zostały wybrane i połączyć to w php (póki co najlepszy pomysł)
SongoQ
Cytat
Coś sugerujesz? snitch.gif Jakaś recepta na problem?

Nie chodzilo mi o problem tylko o znajomosc LEFT JOIN
Athlan
Wybrałem trzeci sposób z przedstawionych 2 posty wyżej.

Oto rozwiązanie:

  1. <?php
  2. // pobieramy notki (tutaj bez stronnicowania, lecz dojdzie obiekt pagera)
  3. $this->oView->aNotes = $aNotes = $this->setModel('note')->get(null, $this->_aBlogData['blog_id']);
  4. // zbierami ID pobranych notek
  5. $aUsedNotes = array();
  6. foreach($aNotes as $iKey => $aRow)
  7. $aUsedNotes[] = $aRow['note_id'];
  8. // pobieramy tagi przypisane do zebranych postów
  9. $aTags = $this->setModel('tag')->getUsed($aUsedNotes);
  10. // przypisujemy tagi: ID_NOTKI => array(TAG, TAG, TAG [... itd ...]);
  11. $aUsedTags = array();
  12. foreach($aTags as $iKey => $aRow)
  13. {
  14. if(!is_array($aUsedTags[$aRow['tag_note']]))
  15.  $aUsedTags[$aRow['tag_note']] = array();
  16.  
  17. $aUsedTags[$aRow['tag_note']][] = $aRow['tag_name'];
  18. }
  19. // koniec :)
  20. $this->oView->aTags = $aUsedTags;
  21. ?>


Chyba najbardziej optymalne rozwiązanie. Dziękuję za dyskusję smile.gif

Athlan smile.gif
envp
@Athlan: jedna z zasad optymalizacji skryptów - jeśli da się zrobić coś na poziomie bazy - to to zrób. Kiedys robiłem testy na zapytania do mysl'a i uwierz lepiej zrobić jedno duże zapytanie niż kilka mniejszych...
Athlan
Cytat
@Athlan: jedna z zasad optymalizacji skryptów - jeśli da się zrobić coś na poziomie bazy - to to zrób. Kiedys robiłem testy na zapytania do mysl'a i uwierz lepiej zrobić jedno duże zapytanie niż kilka mniejszych...


Sugerujesz, żeby joinować notki do tagów i wykonać wszystkie operacje?
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.