Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [MySQL][PHP] Jeden rekord w wielu kategoriach/dodawanie wielu rekordów do kilku kategorii na raz
Przekras
post 15.10.2014, 16:40:29
Post #1





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 24.06.2014

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


Witam,
potrzebuję zrobić na swoją stronę(a właściwie zrobiłem) skrypt dodający tresci, które mogą należeć do paru kategorii. Zależy mi abym mógł na raz dodawać np 100 rekordów. W bazie mam jedną główną tabelę o nazwie Filmy, struktura:

  1. CREATE TABLE IF NOT EXISTS `Filmy` (
  2. `id_filmu` int(6) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `numer_filmu` int(8) UNSIGNED NOT NULL,
  4. `tytul_filmu` varchar(70) NOT NULL,
  5. `kategoria_filmu` varchar(20) NOT NULL,
  6. PRIMARY KEY (`id_filmu`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=60 ;


Oraz każda kategoria zawiera swoje oddzielne tabele, połączone id-em z tabelą główną, każda kategoria będzie wyświetlana na oddzielnej stronie, także taka struktura wydaje mi się najlepsza:
  1. CREATE TABLE IF NOT EXISTS `kategoria8` (
  2. `id_kat8` int(6) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `id_filmu` int(6) UNSIGNED NOT NULL,
  4. PRIMARY KEY (`id_kat8`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;


Poniżej kod dodający dane do dwóch tabel na raz(z objasnieniami co chciałem zrobić):
  1. $zapytanie="INSERT INTO `Filmy` (`id_filmu`, `numer_filmu`, `tytul_filmu`, `kategoria_filmu`) VALUES (NULL, '54321', 'tytul1', '9876'), (NULL, '567890', 'tytul2', '9875')";
  2. // i tutaj jeszcze np 50 innych VALUES, kolumna "kategoria_filmu" z danymi np.9876 oznacza że film bedzie wyswietlany w kategoiach o numerach 9, 8, 7 i 6
  3. mysql_query($zapytanie);
  4. $id = mysql_insert_id(); //pobiera id ostatnio dodanego wyniku - DO TEGO PYT 1
  5.  
  6. $kat = "SELECT kategoria_filmu FROM Filmy where id_filmu='$id'"; //wybiera kategorie filmu z tabeli filmy gdzie id_filmu ma numer ostatnio dodanego wyniku
  7. $rezultat = mysql_query($kat)
  8. or die("Query failed");
  9. $wynik = mysql_fetch_array($rezultat);
  10. $wypisanie = $wynik['kategoria_filmu']; //potrzebne aby niżej sprawdzić jakie numery kategorii zawarte w "kategoria_filmu"
  11. $zapisac = mysql_query("INSERT INTO kategoria8 (id_filmu) VALUES ($id)"); //jeżeli spełniony zostanie ponniższy warunek to id z tabeli Filmy zostanie zapisany do tabeli "kategoria8"
  12. if (preg_match("/8/i", "$wypisanie")) //jeżeli w $wypisanie znajduje sie 8 to dzieje sie $zapisac i taki if do każdej kategorii oddzielnie PYTANIE 2
  13. {
  14. echo $zapisac;
  15. }
  16. else
  17. {
  18. }

Ogólnie kod działa jak należy, jednak tylko dla jednego dodanego wyniku.
PYTANIA:
1. Niestety pobierany jest tylko id pierwszego dodanego wyniku i umieszczany w tabeli kategorii, chciałbym aby przy dodawaniu np 50 Values w Insert wszystkie były dodawane od razu do odpowiednich kategorii, da się tak zrobić? Bo dodawanie oddzielnie 50 rekordów byłoby "trochę" uciążliwe. Próbowałem pętle jednak tak kombinowałem że dodałem do dwóch tabel ponad 6 mln rekordów na raz biggrin.gif
2. Czy dałoby radę umieścić wszystko w jednym ifie tzn. sprawdzić jakie cyfry są zawarte w "kategoria_filmu" i umiescic w odpowiednich tabelach kategorii, próbowałem else, ale jeżeli jest spełniony pierwszy warunek to już nie przechodzi do następnego.

Poniżej skrypt wyświetlający wszystkie wiersze z kategorii:
  1. $wypisac = "SELECT *
  2. FROM kategoria8 INNER JOIN Filmy
  3. ON kategoria8.id_filmu = Filmy.id_filmu";
  4. $rezultatt = mysql_query($wypisac);
  5. while ($row = mysql_fetch_array($rezultatt))
  6. {Tutaj kod wyświetlający wszystkie potrzebne rekordy z dwóch tabel}


PYTANIE ogólne:
3. Czy cały ten kod da się jakoś zoptymalizować, może macie jakieś inne sposoby? (ogólnie wszystko działa jak należy oprócz dodawania wielu Values na raz)

Na koniec proszę o wyrozumiałość, wstyd się przyznać ale napisanie tego zajęło mi 2 dni(nie korzystałem z innych skryptów), próbowałem na wiele sposobów i ten wydaje mi się najlepszy.
Pozdrawiam

Ten post edytował Przekras 15.10.2014, 19:03:37
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 5)
b4rt3kk
post 15.10.2014, 17:43:29
Post #2





Grupa: Zarejestrowani
Postów: 1 933
Pomógł: 460
Dołączył: 2.04.2010
Skąd: Lublin

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


Struktura bazy danych nie jest optymalna. Źle to wszystko rozplanowałeś. Potrzebujesz jednej tabeli filmy, jednej tabeli kategorie oraz jednej tabeli przyporządkowującej film do kategorii. Czyli teoretyczna struktura powinna wyglądać tak:

  1. Tabela movies:
  2. id | title
  3. 1 | kompania braci
  4.  
  5. Tabela categories:
  6. id | name
  7. 1 | wojenne
  8. 2 | thriller
  9.  
  10. Tabela movie_categories:
  11. id | id_movies | id_categories
  12. 1 | 1 | 1
  13. 2 | 1 | 2


Oczywiście w tabeli movie_categories kolumna id jest zbędna, ale można ją zachować dla porządku.

Ten post edytował b4rt3kk 15.10.2014, 17:49:58


--------------------
Jeśli pomogłem, kliknij proszę 'pomógł'. Dzięki.
Go to the top of the page
+Quote Post
Przekras
post 15.10.2014, 18:45:51
Post #3





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 24.06.2014

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


W tabeli movie_categories kolumna id_movies (u mnie-numer_filmu) zawierałaby 8 cyfr bo tak długie są numery filmów, i do tego bez żadnej kolejności. Na jednej stronie będę wyświetlał filmy(odnośniki do filmów) tylko z jednej kategorii np. 40 stron po 40 odnośników to daje 1600 dla jednej kategorii(podział na strony przez stronnicowanie), licząc że kategorii będzie 9 a jeden film będzie należał do 3 kategorii tabela „movie_categories” miałaby 43 200 rekordów.

Natomiast w moim rozwiązaniu dane są sczytywane z jednej tabeli kategorii a następnie tytuł i numer filmu ściągany z tabeli Filmy po numerze id, czyli w tym przypadku tabela kategorii zawierałaby te 1600 rekordów, a tabela Filmy 14 400, czyli mniej do przeszukania. Będę wdzięczny jeżeli wytłumaczysz mi dlaczego Twoje rozwiązanie byłoby optymalniejsze(pamiętając że każda kategoria będzie wyświetlana na oddzielnej stronie), bo jak tak rozpisałem to wydaje mi się że moje, ale dobrze się na tym nie znam wink.gif

Pozdrawiam
Go to the top of the page
+Quote Post
Damonsson
post 15.10.2014, 19:05:34
Post #4





Grupa: Zarejestrowani
Postów: 2 355
Pomógł: 533
Dołączył: 15.01.2010
Skąd: Bydgoszcz

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


Jeżeli masz pewność, że zawsze będziesz wykonywał zapytanie pobierające filmy tylko i wyłącznie z jednej kategorii, to Twoje rozwiązanie może mieć jakiś tam głębszy sens, jak będziesz miał milion filmów dla kategorii.
Go to the top of the page
+Quote Post
b4rt3kk
post 15.10.2014, 19:35:58
Post #5





Grupa: Zarejestrowani
Postów: 1 933
Pomógł: 460
Dołączył: 2.04.2010
Skąd: Lublin

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


Po pierwsze już w samym momencie zapisu danych wykonujesz nadmiarową liczbę zapytań. Po drugie preg_match dodatkowo spowalnia wstawianie rekordów (swoje zajmuje czasowo, zmień na str_pos jak musisz tak robić). Już lepiej (o ile jesteś pewien, że zostajesz przy takiej strukturze bazy) oddzielić poszczególne id np. średnikiem. Wtedy wystarczy explode. Przykład poniżej.

  1. $zapytanie="INSERT INTO `Filmy` (`id_filmu`, `numer_filmu`, `tytul_filmu`, `kategoria_filmu`) VALUES (NULL, '54321', 'tytul1', '9876'), (NULL, '567890', 'tytul2', '9;8;7;5')";
  2. mysql_query($zapytanie);
  3. $kat = "SELECT kategoria_filmu FROM Filmy where id_filmu='$id'"; // na co to zapytanie? kategorię masz już znaną w momencie inserta? całkiem zbędne
  4. $rezultat = mysql_query($kat) or die("Query failed");
  5. $wynik = mysql_fetch_array($rezultat);
  6. $wypisanie = explode(';', $wynik['kategoria_filmu']);
  7.  
  8. foreach ($wypisanie as $id_tab) {
  9. $zapisac = mysql_query("INSERT INTO kategoria{$id_tab} (id_filmu) VALUES ($id)");
  10. }


No i co do samej zasadności użycia 3 tabel. Nie chodzi tutaj o liczbę rekordów, tylko o uniwersalność rozwiązania. Wyobraź sobie, że dodajesz lub usuwasz kategorię. I co wtedy? Wszystko nagle się rypnie, bo albo będziesz musiał modyfikować wszystkie wpisy z tabeli filmy, albo baza utraci spójność. A tak, usuwasz kategorię, usuwasz wszystkie dowiązania i baza dalej działa bez zarzutu. Gdy będziesz chciał dodać kolejną kategorię to będziesz musiał dodawać kolejne tabele dla tej kategorii.

A tak to masz jedno proste zapytanko żeby pobrać całą daną kategorię (pownno być dosyć szybkie), a napewno bardziej uniwersalne, na potrzeby www (potrzebujesz tylko 1 i tej samej podstrony, a zmieniasz tylko parametr w GET):

  1. SELECT
  2. *
  3. FROM movies m
  4. JOIN movies_categories mc ON m.id = mc.id_movies
  5. JOIN categories c ON c.id = mc.id_categories
  6. WHERE c.id = $id_cat;



--------------------
Jeśli pomogłem, kliknij proszę 'pomógł'. Dzięki.
Go to the top of the page
+Quote Post
mmmmmmm
post 15.10.2014, 22:11:07
Post #6





Grupa: Zarejestrowani
Postów: 1 421
Pomógł: 310
Dołączył: 18.04.2012

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


Cytat(Przekras @ 15.10.2014, 19:45:51 ) *
W tabeli movie_categories kolumna id_movies (u mnie-numer_filmu) zawierałaby 8 cyfr bo tak długie są numery filmów, i do tego bez żadnej kolejności. Na jednej stronie będę wyświetlał filmy(odnośniki do filmów) tylko z jednej kategorii np. 40 stron po 40 odnośników to daje 1600 dla jednej kategorii(podział na strony przez stronnicowanie), licząc że kategorii będzie 9 a jeden film będzie należał do 3 kategorii tabela „movie_categories” miałaby 43 200 rekordów.

Coś źle liczysz... Jeśli będziesz miał 1600 filmów i 9 kategorii, a każdy film będzie należał do 3 kategorii, to tabela movie_categories będzie miała 1600*3 rekordów. Czyli jakieś 4800.

Cytat(Przekras @ 15.10.2014, 19:45:51 ) *
Natomiast w moim rozwiązaniu dane są sczytywane z jednej tabeli kategorii a następnie tytuł i numer filmu ściągany z tabeli Filmy po numerze id, czyli w tym przypadku tabela kategorii zawierałaby te 1600 rekordów, a tabela Filmy 14 400, czyli mniej do przeszukania. Będę wdzięczny jeżeli wytłumaczysz mi dlaczego Twoje rozwiązanie byłoby optymalniejsze(pamiętając że każda kategoria będzie wyświetlana na oddzielnej stronie), bo jak tak rozpisałem to wydaje mi się że moje, ale dobrze się na tym nie znam wink.gif

A tu nie wiem, skąd wziąłeś 1600 kategorii? Naprawdę sądzisz, że fimy da się opisać aż tyloma kategoriami?
@b4rt3kk ci wszystko ładnie rozpisał. Spróbuj.
Go to the top of the page
+Quote Post

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

 



RSS Wersja Lo-Fi Aktualny czas: 25.07.2025 - 10:02