Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Złączenia CROSS JOIN + Smarty [php][smarty]
rodipl
post
Post #1





Grupa: Zarejestrowani
Postów: 10
Pomógł: 3
Dołączył: 29.12.2008
Skąd: osada koczownika :P

Ostrzeżenie: (0%)
-----


Witam.

Mam pewien problem ze złączeniem typu CROSS JOIN w mysqli, a do tego wynik jest przesyłany do Smarty.

Oto moje zapytanie (oczywiście działa i dobrze się ma)
Kod
SELECT * FROM news CROSS JOIN admin CROSS JOIN kat_news WHERE news.id_login = admin.id ORDER BY news.data AND news.id_kat = kat_news.id AND slider = '0' DESC LIMIT 4


Następnie dane trafiają do SMARTY poprzez: $smarty->assign("news", $news);

W pliku .tpl mam
Kod
{foreach item=news from=$news}
<div class="news">
<a class="news" href="nowosc,{$news.id},{$news.tytul|lower|nl2br|strip_tags|replace:' ':'_'}">
<span class="ngnews">
{$news.tytul|nl2br|strip_tags}
</span>
</a>
</div>
{/foreach}


To także działa - wyniki wyświetlają się poprawnie oprócz małego niuansu. W linku nowosc,IDNEWSA,TYTUL_NEWSA -> zamiast IDNEWSa wyświetla się ID kategorii newsa ze złączenia. Próbowałem modyfikować zapytanie lecz nieskutcznie. Może ktoś ma jakiś lepszy sposób?

Proszę o konsultację. (IMG:style_emoticons/default/biggrin.gif)

Życzę miłego wieczoru.
Pozdrawiam,
Robert.
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 5)
thek
post
Post #2





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Cross join ma to do siebie, że łączy wszystko ze wszystkim, co w przypadku większych tabel jest niestety zajeżdżaniem bazy. Radziłbym Ci je przerobić, bo i tak zauważ, że limitujesz te dane a na dodatek wyświetlasz tylko kilka rzeczy, więc przerzucanie wszystkich używając gwiazdki w select to dodatkowe obciążanie łącza nadmiarem przesyłanej informacji. Zresztą patrząc na kod jakiekolwiek złączanie z kategorią jest bezsensowne, gdyż nie używasz danych z tej tabeli. Smarty uzywa tylko id i tytuł, a to sugeruje skrócenie zapytania do:
  1. SELECT id, tytul FROM news WHERE author_id = admin_id ORDER BY id DESC LIMIT 4
gdzie admin_id to numer id admina gdy masz tylko jednego w bazie. Jeśli jednak masz kilku adminów w serwisie to modyfikujesz nieznacznie całość do:
  1. SELECT id, tytul FROM news WHERE author_id IN (SELECT id FROM admin) ORDER BY id DESC LIMIT 4

Nie potrzeba nawet sortowania po dacie newsa, bo automatycznie newsy z najwyższymi id są jednocześnie najświeższymi. A id jest zazwyczaj indeksem w przeciwieństwie do daty, co sprawi, ze zapytanie jest jeszcze szybciej wykonywane.
Tak przynajmniej można Twój kod poprawić (IMG:style_emoticons/default/winksmiley.jpg) Bo na co robić tyle niepotrzebnych joinów generujących bezsensownie tyle wierszy, skoro nie musi być żadnego? No chyba, że dołączasz kategorię jeszcze z innych powodów, ale przeanalizuj swój kod, niezbędne zmienne i sam zobaczysz jak wiele nadmiarowych rzeczy robisz niepotrzebnie. Bo przecież choćby w Twoim wypadku przesyłasz teżtreść wszystkich rekordów włącznie z treścią newsa, którego nie wyświetlasz nigdzie. A przesłanie tego między Apachem i MySQL też swój czas zajmie. Nie przesyłaj więc niepotrzebnie danych, których nie używasz.

Ale jeśli już jakoś musisz użyć całości jak jest to poczytaj o czymś takim jak ALIAS (IMG:style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
rodipl
post
Post #3





Grupa: Zarejestrowani
Postów: 10
Pomógł: 3
Dołączył: 29.12.2008
Skąd: osada koczownika :P

Ostrzeżenie: (0%)
-----


To było uproszczone... Przedstawiłem tylko to co nie działa tak jak powinno + kilka linijek więcej, aby było wiadomo o co chodzi. Wyświetlam wszystko co jest w bazie danych, a nie chciało mi się po prostu tego wypisywać dlatego użyłem gwiazdkę. Wypisuję np. link obrazka, zajawkę, treść, autora, datę itd.

moja baza wygląda tak:

news
id -> klucz podstawowy + auto inctrement
id_kat
id_login
....

kat_news
id -> klucz podstawowy + auto inctrement
nazwa

admin

id -> klucz podstawowy + auto inctrement
login
...

Dlaczego złączenia są bez sensu? Nie przepisuje danych do tabeli "news" tylko działa to na zasadzie relacji id_kat łączy się z id od kat_news dzięki, któremu wyświetlam nazwa. Tak samo z adminem tylko, że wyświetlam login osoby, która dodała nowość.

Niestety jak na razie czekam na dalsze wskazówki. (IMG:style_emoticons/default/smile.gif)

Ten post edytował rodipl 23.08.2009, 00:25:38
Go to the top of the page
+Quote Post
thek
post
Post #4





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Dla mnie za dużo kombinowania z łączeniami typu CROSS JOIN robisz, gdzie są one tylko spowalniaczem całości skryptu i w takiej sytuacji nie stosuje się ich. Przy takiej strukturze tabel robisz LEFT JOIN po kolumnach łączących i wyciągasz odpowiednie dane. Nazwa tabeli admin była dla mnie myląca i sugerowała, że tylko admin może pisać i dlatego ująłem id_admina jako warunek ograniczający. W takim wypadku zapytanie powinno być:
  1. SELECT n.*, k.nazwa AS kategoria, a.login FROM news n LEFT JOIN kategoria k ON n.id_kat = k.id LEFT JOIN admin a ON n.id_login = a.id ORDER BY n.id DESC LIMIT 4

Takie zapytanie ograniczy już "na dzień dobry" liczbę tworzonych rekordów do liczby newsów, bo cross join tworzy w bazie tymczasowo (newsy * userzy * kategorie) rekordów, czyli, przykładowo 50 newsów * 40 userów * 5 kategorii, to 10000 rekordów tymczasowych(!) i jedzie po bazie przez to równo. LEFT JOINy zaś do newsów wyszukają z bazy konkretną kategorię i usera przypisanego. Problemem może być przypisanie newsa do kilku kategorii, ale w takim wypadku baza (i zapytanie) nieco inaczej wygląda, ponieważ usuwa się z tabeli news id_kategorii i tworzy tabelę złączeniową, w której jako kolumny są id_newsa i id_kategorii.
Błąd wyskakiwał ci ponieważ przy jakimkolwiek joinie kilka kolumn o tej samej nazwie zawsze robi bajzel przy próbie wyciągania danych z rekordu. Stąd najlepiej wybrać tylko niezbędne Ci dane, a dla dubli na wszelki wypadek ustawić aliasy. To fragment:
k.nazwa AS kategoria
co sprawi, że nazwa kategorii będzie widoczna jako kategoria. W Twoim wypadku problem był z kolumnami id, które były w każdej z tabel i jeśli byś chciał się do nich odnieść to musiałbyś po prostu znać ich dokładne nazwy po zastosowaniu join, ale lepiej w takich wypadkach właśnie na te duble zastosować aliasy. Ja użyłem wszystkich danych z tabeli news, a z pozostałych wyciągnąłem tylko te niezbędne mi do działania skryptu, czyli login usera i nazwę kategorii. Ty akurat możesz chcieć coś więcej z tych dwóch ostatnich.

Ten post edytował thek 23.08.2009, 11:24:57
Go to the top of the page
+Quote Post
rodipl
post
Post #5





Grupa: Zarejestrowani
Postów: 10
Pomógł: 3
Dołączył: 29.12.2008
Skąd: osada koczownika :P

Ostrzeżenie: (0%)
-----


Nie głupie. (IMG:style_emoticons/default/smile.gif)

Chociaż równie dobrze można by było zmienić w tabeli id na idcostam i byłby już spokój. ^^

Dzięki za pomoc.
Można zamknąć.

Edit:
Mam jeszcze jedno pytanie (więc nie zamykać (IMG:style_emoticons/default/tongue.gif) ) -> czy jeżeli zrobię w 1 zapytaniu np. 6 aliasów (dzięki, którym zmianie nazwy w locie) to czy to w jakiś sposób bardzo obciąży mi samo zapytanie?

Ten post edytował rodipl 23.08.2009, 09:59:27
Go to the top of the page
+Quote Post
thek
post
Post #6





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Można zmienić id w nazwie tabeli, ale później grzeb sobie po plikach gdzie już tej nazwy kolumny użyłeś i zmieniaj (IMG:style_emoticons/default/winksmiley.jpg) Sam alias to tylko zmiana nazwy kolumny, co nie jest obciążające dla bazy. W końcu nazywasz kolumnę tylko raz i potem zapominasz o tym. Ciekawostka dla Ciebie może być fakt, że aliasu możesz używać w dalszej części zapytania jakby był nazwą normalną, czyli równoznaczny z nazwa(alias)_tabeli.pole_tabeli .
Aha i zrobiłem mały błąd w ostatnim poście. Ma być ORDER BY n.id, a nie samo id, by uniknąć problemów. Zresztą zaraz post wyedytuję (IMG:style_emoticons/default/winksmiley.jpg)

EDIT: Jeszcze jedno... left join zawsze wyświetli wyniki, nawet jeśli w dołączanej tabeli nie znajdzie niczego po połączeniu. Na przykład news był napisany przez usera, którego usunąłeś z bazy lub z usuniętej kategorii i tym samym takie id w drugiej tabeli już nie istnieją. Wtedy pola w brakujących kolumnach uzupełni wartościami NULL. W takim przypadku po odebraniu danych sprawdź owe pola i jeśli napotkasz wartości puste przypisz podczas wyświetlania wyniku na stronie "Użytkownik usunięty" lub "Kategoria została usunięta".

W przypadku Smarty możesz to zrobić albo poprzez sprawdzenie danych zaraz po odebraniu z bazy lub dopiero w template, piszac dodatkowy warunek IF (IMG:style_emoticons/default/smile.gif)

Ten post edytował thek 23.08.2009, 11:32:47
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 23.08.2025 - 12:15