Autor Zpráva
lopikol
Profil
SELECT M.*, GD.*, G.name AS genres FROM movies M LEFT JOIN genres_data GD ON GD.movies_id = M.id LEFT JOIN genres G ON G.id = GD.genres_id GROUP BY M.id ORDER BY M.id



Problém je vom, že výpis z `G.name AS genres` je array, ale dibi nebo nette mi vypíše pouze úplně ten první. Co mám do dotazu připsat nebo co upravit, aby to vypsalo všechny `G.name AS genres` > všechny žánry daného filmu. Děkuji
o_O
Profil
lopikol:
Jakub vrána - group_concat
lopikol
Profil
o_O:
Díky, ale díky tomu vzniká jeden problém. Vytvoří to skupinu: bmw,fiat,audi,škoda. Jenže už sní nemohu nijak pracovat > např, když bych chtěl vybrat jen audi.
panther
Profil
lopikol:
buď chceš vybrat všechny, nebo jen audi. To jsou dva různé dotazy.

Případně si můžeš data groupovat na úrovni PHP aplikace.
lopikol
Profil
jenže když nepoužiju group_concat, tak mi to vypíše jen první záznam > BMW a tím to končí.
o_O
Profil
lopikol:
Jenže už sní nemohu nijak pracovat
Můžete. Stačí použít např. funkci explode(), popřípadě by šlo upravit dotaz, jen musíte specifikovat co přesně musí příkaz dodat.
Tori
Profil
lopikol:
výpis z `G.name AS genres` je array, ale dibi nebo nette mi vypíše pouze úplně ten první.
Nějak to nechápu - mělo by vám to prostě vracet postupně všechny hodnoty (názvy žánrů nebo co), jen bude každý na jiném řádku.
Jestli používáte dibi, podívejte se na příklady s fetchAssoc - třeba se bude dát použít něco jako
$vysledek = dibi::query("SELECT M.*, M.id AS 'movie_id', GD.*, G.name AS 'genres', G.id AS 'genre_id'
    FROM movies M 
    LEFT JOIN genres_data GD ON GD.movies_id = M.id 
    LEFT JOIN genres G ON G.id = GD.genres_id 
    GROUP BY M.id ORDER BY M.id")->fetchAssoc('movie_id,=,genre_id');
lopikol
Profil
Tori:
Právě, že já to taky nechápu. Prostě mi to vypíše jen ten první jak jsem říkal a né všechny :(

fetchAssoc
Zkoušel jsem snad všechny možnosti a nejde to.
o_O
Profil
Stále nechápu, čeho chcete dosáhnout. Řekl jste, že potřebujete vybrat „všechny žánry daného filmu“, což group_concat udělal.

Mohl by jste říci, čeho přesně chcete dosáhnout? Bez této informace Vám nemůžeme poradit.
lopikol
Profil
GROUP_CONCAT(G.name ORDER BY G.name) AS genres


Chci dosáhnout toho, abych s daty z téhle části dotazu mohl pracovat jednotlivě. To jest. genres vypíše řadu akční,krimi,thriller. Jenže, díky tomu je to skupina, a tak nemohu např vybrat jen filmy, které mají žánr katastrofický.
o_O
Profil
Jediné, co mě v tuto chvíli napadá je využít HAVING.

Př:
SELECT M.*, GD.*, group_concat(G.name) AS genres FROM movies M LEFT JOIN genres_data GD ON GD.movies_id = M.id LEFT JOIN genres G ON G.id = GD.genres_id GROUP BY M.id having genres LIKE '%Komedie%' ORDER BY M.id


Ovšem LIKE dost zpomaluje (zvláště u větší tabulky), možná by to šlo napsat lépe. Popřemýšlím o tom, prozatím by šlo využít toto (doporučuji si pohrát s indexy).
lopikol
Profil
Tak jsem trochu bádal.

Pokud použiju having, tak to vypíše jen ty, kde je první žánr komedie tzv. ?having=1 (id komedie) a vypíše to všechny filmy, kde je pořadí žánrů Komedie, Rodinný, Animovaný, ale pokud je pořadí žánrů Animovaný, Komedie, Rodinný, tak ho to nezobrazí.


Zkusil jsem použít i where, ale to zas vypíše jen ten daný žánr, ale vybere to všechny filmy s vybraným žánrem.

Např. mám film Auta žánr Rodinný, Komedie, Animovaný. V url mám ?where=1 (id komedie) a na stránce se zobrazí Auta - komedie > nevypíše to další žánry rodinný, animovaný

Řešením bude nějak nahradit GROUP_CONCAT(), jenže bez toho mi to ty žánry nevypíše všechny.

      $m = dibi::select('M.name, M.time, M.link, GROUP_CONCAT(G.name ORDER BY G.name) AS genres, Q.name as mquality, G.id AS gid, GD.genre_id AS gdid')
                        ->from('[::movies] M')
                          ->leftJoin('[::genres_data] GD')
                            ->on('GD.movie_id = M.id')
                          ->leftJoin('[::genres] G')
                            ->on('G.id = GD.genre_id')
                          ->leftJoin('[::qualities] Q')
                            ->on('Q.id = M.quality_id')
                          ->groupBy('M.id');
      
      if($having) {
        $m->having('G.id LIKE %i', $having);  
      }

      if($sort_desc) {         
        $m->orderBy(array($sort_by => 'DESC'));                
      }else{            
        $m->orderBy($sort_by);
      }
             $m->test();
      return dump($m->fetchAll());
o_O
Profil
lopikol:
Pokud použiju having, tak to vypíše jen ty, kde je první žánr komedie
Můj příklad s HAVING funguje i v případě, že se daný žánr vyskytuje uprostřed skupiny.

Pravděpodobně jste ho špatně opsal (chybějící %).
lopikol
Profil
o_O:
Moc děkuji za pomoc, jsem rád, že dnes ještě někdo pomůže ;) Vyřešil to %~like~
lopikol
Profil
Chtěl jsem si vytvořit tzv multiple choice, Zaškrtneš více kategorií a vybere je to z db. Přidal jsme do kodu:

      if($having) {
        $m->having('%or', array(array('genres LIKE %~like~', $having)));  
      }
 


Když do url zadám ?having=komedie nebo ?having=western, tak to najde správně jak má. Když zadám ?having=komedie&having=western, tak se to zkrátí na ?having=western a jsem zase na začátku. Jak bys to řešil?

Ještě jsem došel k jednomu problému. A to, když je fiml spadá pod žánr akční nebo romantický, ale to snad vyřešim.
o_O
Profil
V případě, že se vybere více možností, má to vybírat film v případě přesné shody (tzn. film musí mít žánry Western a Komedie), nebo musí obsahovat právě jeden z vybraných žánrů?

Co se týče odkazu, je jasné, že nelze používat 2× stejný klíč (having a having), ale musí se z něj udělat pole (having[]), tzn:
<form action="" method="get">
<select name="having[]"><option value="western">Western</option><option value="komedie">Komedie</option></select>
<select name="having[]"><option value="akcni">Akční</option><option value="romanticky">Romantický</option></select>
<input type="submit" name="odeslat" value="Vyhledat"></form>
o_O
Profil
* Výstup pak bude: Array ( [having] => Array ( [0] => western [1] => akcni ) [odeslat] => Vyhledat )
* URL pak bude: ?having[]=western&having[]=akcni&odeslat=Vyhledat

lopikol:
Ještě jsem došel k jednomu problému
Jakému? LIKE nemá rádo diakritiku?
lopikol
Profil
o_O:
V případě, že se vybere více možností, má to vybírat film v případě přesné shody (tzn. film musí mít žánry Western a Komedie), nebo musí obsahovat právě jeden z vybraných žánrů?

Samozřejmě, že alespon jeden. Proto %or

Část pro výběr vypadá takto:
      if($having) { dump($having);
        $m->having('%or', array(array('genres LIKE %~like~', $having)));  
      }


Výsledné SQL:
array(2) [
   0 => "western" (7)
   1 => "komedie" (7)
]

SELECT M.name, M.time, M.link, GROUP_CONCAT(G.name 
ORDER BY G.name) AS genres, Q.name as mquality 
FROM `movies` M 
LEFT JOIN `genres_data` GD ON GD.movie_id = M.id 
LEFT JOIN `genres` G ON G.id = GD.genre_id 
LEFT JOIN `qualities` Q ON Q.id = M.quality_id 
GROUP BY `M`.`id` 
HAVING (genres LIKE '%western%', '%komedie%') 
ORDER BY `name`

Jak je vidět, tak řádek HAVING je špatně. Bohužel, to nemohu dát dohromady.

Jakému? LIKE nemá rádo diakritiku?
No url nemá rádo diakritiku z akční udělá akn
o_O
Profil
Prosím, posílejte zde alespoň společně s příkazem i strukturu tabulek. Jak se tak koukám, dost se změnila a já to díky toho nemohu odzkoušet v PMA.

Co se týče toho problému, chyba je jasná: Operand should contain 1 column. To znamená, že musíte využít 2 LIKE.

Stačí to upravit na:
HAVING (genres LIKE '%western%' OR genres LIKE '%komedie%') 
lopikol
Profil
Tu je to sql. Moc se nezměnilo.

DROP TABLE IF EXISTS `genres`;
CREATE TABLE `genres` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` tinytext COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


DROP TABLE IF EXISTS `genres_data`;
CREATE TABLE `genres_data` (
  `movie_id` int(11) NOT NULL,
  `genre_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


DROP TABLE IF EXISTS `movies`;
CREATE TABLE `movies` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` tinytext COLLATE utf8_czech_ci NOT NULL,
  `time` int(11) NOT NULL,
  `quality_id` int(11) NOT NULL,
  `link` tinytext COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


DROP TABLE IF EXISTS `qualities`;
CREATE TABLE `qualities` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` tinytext COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;



o_O:
> Stačí to upravit na:
>
> 1
>
> HAVING (genres LIKE '%western%' OR genres LIKE '%komedie%')

já myslel, že toto to dokáže.

      if($having) { dump($having);
        $m->having('%or', array(array('genres LIKE %~like~', $having)));  
      }


přeco tu musí jit jednodušeji, než psát:

if($having[0]){HAVING (genres LIKE '%western%')}
if($having[1]){HAVING (genres LIKE '%western%' OR genres LIKE '%komedie%') }
if($having[2]){HAVING (genres LIKE '%western%' OR genres LIKE '%komedie%' OR genres LIKE '%si-fi%') }

o_O
Profil
lopikol:
přeco tu musí jit jednodušeji
Jestli to můžete napsat takto, tak jistě:
if($_GET['having']){
  $having='';
  foreach($_GET['having'] AS $value)
    $having.='OR genres LIKE '%'.$value.'%';
}

Do dotazu pak dosadíte string bez prvních 3 znaků (mb_substr($having,3)).
o_O
Profil
Eh, zapomněl jsem na apostrofy/uvozovky. Řekněme třeba takto:
if($_GET['having']){
  $having='';
  foreach($_GET['having'] AS $value)
    $having.='OR genres LIKE "%'.$value.'%"';
}

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0