Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP]sformułowanie zapytania
Forum PHP.pl > Forum > Przedszkole
kleszczoscisk
Witam

Pobieram z kilku tabel produkty, producentów i opisy produktów w 2 językach. Pobieram obie wersje językowe opisów bo póki co wersji obcojęzycznych jest znikoma ilość i to co się da tłumaczę przez php z automatu.
Problem:
Jak wykluczyć w zapytaniu polską wersję opisu produktu jeśli istnieje obcojęzyczna ?
W tabeli 'produkty' każdy produkt ma unikalny ID. W tabeli 'opisy' każdy opis ma odpowiedni ID produktu i oprócz tego oznaczenie języka np. 'pl', 'en'.
Czy rozwiązaniem byłoby podzapytanie w rodzaju [SQL] pobierz, plaintext
  1. SELECT DISTINCT product_id FROM products
[SQL] pobierz, plaintext , które byłoby jednocześnie warunkiem w zapytaniu głównym: [SQL] pobierz, plaintext
  1. ... AND WHERE products.product_id IN(SELECT DISTINCT product_id FROM products) ...
[SQL] pobierz, plaintext Czy może powinienem filtrować uzyskane wyniki zapytania zamiast modyfikować zapytanie... ?
Musiałbym wtedy wywalić z tablicy (uzyskanej przez while($r = mysql_fetch_array($rekord)){}) te rekordy z opisem 'pl', które mają swój odpowiednik 'en'... Jak ?
?
Proszę o pomoc, podpowiedzi.
thek
Jeśli product_id jest niezależny od języka, a sądząc z opisu jaki podałeś jest to prawda, to zapytanie może tak wyglądać. Ale spojrzawszy szerzej na to co napisałeś to odnosi się wrażenie, że id jest kluczem głównym i samo w sobie jest już unikatowe, więc nie trzeba go jeszcze distinct traktować (mogę się jednak mylić bo nic nie pisałeś o kluczach), czyli można tę klauzulę wyrzucić i ograniczyć do SELECT product_id FROM products. Dodatkowo dziwne byłoby to zapytanie w WHERE.
By zrobić to o czym piszesz czyli mieć listę wszystkich produktów w bazie, ale tak, że bierzemy wszystkie produkty z obcojęzycznym opisem i dokładamy do niego te z opisem polskim by zrobić komplet, trzeba posłużyć się UNION smile.gif
Opiszę Ci jak to by wyglądało, ale algorytmem. Zapytanie będzie jako zadanie domowe winksmiley.jpg
1. Weź z tablicy opisów id_produktów wszystkich rekordów gdzie są obcojęzyczne opisy. Możesz uściślić o jaki język Ci konkretnie chodzi.
2. Teraz rekordy o pobranych id _produktu połącz z tabelami opisów i innymi Cię interesującymi jak chcesz by otrzymać interesujące Cię dane.
3. Z tabel połączonych z polskimi opisami wybierz te, które nie posiadają takich id jak te wybrane wcześniej i połącz z tabelami innymi wedle uznania.
4. Połącz wyniki obu zapytań.
kleszczoscisk
Dzięki, zaraz będę to analizował. Wydaje mi się jednak (może źle), że chyba lepiej byłoby znaleźć jakiś sposób na odfiltrowanie z tablicy rekordów: jeśli jest rekord z językiem 'en' to wywal rekord o tym samym ID z językiem 'pl'

Powinienem chyba jeszcze dołączyć strukturę tabel:

products:
id*| id_kategorii | id_producenta | obrazek | ...

products_translations:
id* | product_id | lang | opis | ...

Witam

No niestety nie udało mi się nic z tym problemem zrobić. Próbuję z innej strony: filtrowanie tablicy jaką dostaję po wyciągnięciu z bazy. Wygląda ona mniej więcej tak:
Kod
   Array
   (
       [id] => 101
       [id_opisu] => 1
       [lang] => pl
       [opis] => to jest opis polski pierwszego produktu
   )
   Array
   (
       [id] => 101
       [id_opisu] => 2
       [lang] => en
       [opis] => first product -  description in english
   )
   Array
   (
       [id] => 102
       [id_opisu] => 3
       [lang] => en
       [opis] => second product -  description in english
   )
   Array
   (
       [id] => 103
       [id_opisu] => 4
       [lang] => pl
       [opis] => trzeci produkt, opis polski
   )


Gdzie
  • id - numer produktu unikalny z tabeli 'produkty'
  • id_opisu - unikalny numer tłumaczenia z tabeli 'opisy'
  • lang - symbol języka z tabeli 'opisy'
  • opis - tresc opisu z tabeli 'opisy'
Pomijam nieistotne elementy tablicy. W sumie do zapytania pobierane są dane z 4 tabel.

... i jak wywalić z tej tablicy rekord z opisem polskim jeśli istnieje jego odpowiednik o tym samym 'id' z 'opise'm w języku angielskim ?
Czyli w tym przypadku pierwszy rekord ?
thek
No to popatrz dokładnie na mój opis. Połącz tabele products i products translations tak jak zazwyczaj, ale wybierz z niej TYLKO te, które mają lang = en. To jest Twoja pierwsza część.
  1. SELECT wybrane_kolumny FROM products p LEFT JOIN products_translations t ON p.id = t.product_id WHERE t.lang = 'en'

Teraz musisz z tabel połączonych jak poprzednio wybrać wszystkie z lang = pl, ale dodatkowo musisz zaznaczyć, że nie mogą to być rekordy, które mają id takie same jak te z pierwszej paczki.
  1. SELECT wybrane_kolumny FROM products p LEFT JOIN products_translations t ON p.id = t.product_id WHERE t.lang = 'pl' AND p.id NOT IN ( SELECT p.id FROM products p LEFT JOIN products_translations t ON p.id = t.product_id WHERE t.lang = 'en' )

Całość ładnie łączymy UNION. Tylko pamiętaj... Liczba i ilość kolumn muszą się zgadzać bo inaczej Ci wywali baza błąd. Powiedz więc... Czy właśnie podany przepis na zapytanie z wynikami nie jest aby tym co chcesz i co opisałem dokładnie w moim poście sprzed pół tygodnia? winksmiley.jpg
kleszczoscisk
@thek dziękuję pięknie.
Podpowiedz mi jeszcze proszę: "Liczba i ilość kolumn muszą się zgadzać" - czyli muszę wybrać dokładnie te same kolumny w obu zapytaniach , po SELECT ?
wybrane_kolumny ?
thek
Tak tam gdzie wpisałem wybrane_kolumny muszą się one pojawić w takiej samej ilości i takiej samej kolejności. UNION jest specyficznym połączeniem, ponieważ zwyczajnie dodaje rekordy jednego zapytania do drugiego (ale olewa zdublowane!) i nie patrzy na nazwę kolumn tego co dołącza. Ważna jest dla niego tylko ilość kolumn. Jeśli przez przypadek podasz w pierwszym kolumny: Ala, ma, kota, a w drugim: Sierotka, ma, rysia, to tak dostaniesz, choć tylko ma oba te podzapytania mają wspólne. Nazwy kolumn przechodzą z tabeli pierwszej, więc odnosząc się do Ala rekordy z drugiego podzapytania będa miały zawartość tego co było w Sierotka, a tam na pewno nie są dane jakich byś się spodziewał.
kleszczoscisk
Zapytanie wyszło kolosalne, a błąd wyskoczył taki:
Kod
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'


Kod
$rekord = mysql_query("(SELECT
prod_translations.pid ,
prod_translations.product_name ,
prod_translations.lang AS jezyk ,
prod_translations.description ,
prod_translations.active,
prod_translations.isdefault ,

products.product_id,
products.category_id,
products.producer_id,
products.in_stock,
products.gfx,
products.file,
products.add_date,
products.edit_date,
products.price,
products.promo,
products.weight,
products.views,
products.category2,
products.category3,
products.sort,
products.products_related,
products.other_price,
products.product_code,

gfx.gfx_id ,
gfx.prod_id,
gfx.name AS nazwapliku ,
gfx.main_gfx ,
gfx.unic_name ,
gfx.gfx_sort ,

manufacturers.producent_id ,
manufacturers.name AS autor ,
manufacturers.info ,
manufacturers.info_eng ,
manufacturers.web

FROM `manufacturers`
LEFT JOIN  `products` ON manufacturers.producent_id = products.producer_id  
LEFT JOIN  `prod_translations` ON products.product_id = prod_translations.pid  
LEFT JOIN  `gfx` ON  products.product_id = gfx.prod_id  
WHERE manufacturers.isdefault LIKE '%$art%'
AND prod_translations.lang = 'en'
AND gfx.main_gfx = 1  
AND products.in_stock > 0  
ORDER BY products.add_date DESC  LIMIT ".($pagz*$ilez).", $ilez)
UNION
(SELECT
prod_translations.pid ,
prod_translations.product_name ,
prod_translations.lang AS jezyk ,
prod_translations.description ,
prod_translations.active,
prod_translations.isdefault ,

products.product_id,
products.category_id,
products.producer_id,
products.in_stock,
products.gfx,
products.file,
products.add_date,
products.edit_date,
products.price,
products.promo,
products.weight,
products.views,
products.category2,
products.category3,
products.sort,
products.products_related,
products.other_price,
products.product_code,

gfx.gfx_id ,
gfx.prod_id,
gfx.name AS nazwapliku ,
gfx.main_gfx ,
gfx.unic_name ,
gfx.gfx_sort ,

manufacturers.producent_id ,
manufacturers.name AS autor ,
manufacturers.info ,
manufacturers.info_eng ,
manufacturers.web

FROM `manufacturers`
LEFT JOIN  `products` ON manufacturers.producent_id = products.producer_id  
LEFT JOIN  `prod_translations` ON products.product_id = prod_translations.pid  
LEFT JOIN  `gfx` ON  products.product_id = gfx.prod_id  
WHERE manufacturers.isdefault LIKE '%$art%'
AND prod_translations.lang = 'pl'
AND gfx.main_gfx = 1  
AND products.in_stock > 0  
AND products.product_id NOT IN
(SELECT products.product_id FROM `manufacturers` LEFT JOIN  `products` ON manufacturers.producent_id = products.producer_id  LEFT JOIN  `prod_translations` ON products.product_id = prod_translations.pid  LEFT JOIN  `gfx` ON  products.product_id = gfx.prod_id  WHERE manufacturers.isdefault LIKE '%$art%' AND prod_translations.lang = 'en' AND gfx.main_gfx = 1  AND products.in_stock > 0   ORDER BY products.add_date DESC  LIMIT ".($pagz*$ilez).", $ilez)

ORDER BY products.add_date DESC  LIMIT ".($pagz*$ilez).", $ilez)") or die(mysql_error());


Tak myślę, że gdyby jednak zabrać się do tego przez przefiltrowanie wyników to może nadawać się będzie array_filter. Funkcja do której by się odwoływała musiałaby szukac w kluczu $w['id'] duplikatów i spośród nich usuwać elementy, które mają w kluczu $w['lang'] pl ... ? Help smile.gif
thek
Jeśli tak to porządny serwer sobie załatw, bo takie errory to bodajże gdzieś w Mysql 3.X były, a 5.X już od jakiegoś czasu jest... Ostatni raz tego typu błąd widziałem chyba 2-3 lata temu. Dlatego myślę,że jakiś naprawdę stary serwer masz w użytku. Czyżby Krasnal? winksmiley.jpg
Patrząc na kod chyba wszystko wrzucasz jako kolumny. Jeśli tak jest to zastosuj składnię: nazwa_tablicy.* lub wręcz samo *. Ale wybieranie wszystkiego to bezsens. Bierz tylko potrzebne kolumny. Dzięki temu przyspieszasz zapytanie poprzez zmniejszenie ilości przesyłanych danych. I zapytanie zmniejszysz.
kleszczoscisk
To płatny współdzielony hosting w popularnej polskiej firmie... Wybieram tylko niezbędne pola, z których dane użyte będą później w pętli while. Bardzo doceniam Twoje podpowiedzi ale noie przestaje mnie nurtować, czy pobierając dane z bazy prostszym i mniej obciążającym zapytaniem i później filtrując tę tablicę jakoś ... nie wyjdzie na to samo ?
thek
Wszystko zależy od potrzebnych nam danych i ich struktury. Czasem nie ma sensu robić kosmicznych zapytań, ale zazwyczaj silnik bazy jest szybszy niż interpreter kodu php. Operacje tablicowe więc trwają z reguły dłużej niż identyczne w wyniku zapytanie do bazy. Dlatego ludzie czasem bardziej wolą zrobić ciut bardziej skomplikowane zapytanie niż próbować je zaprogramować skryptem.
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.