Query group actor e film

Alex_70

Utente Attivo
13 Nov 2018
371
14
18
HELL
Salve a tutti,

ho questa query in cui visualizzo gli attori che hanno lavorato con l'attore ma non lui, funziona ma vorrei perfezionarla

esempio:
Linda Blair ha lavorato con Max Von Sydow nei film L'Exorcist (1973) e L'exorcist - The Eretic (1977)
Max Von Sydow si dovrebbe visualizzare solo una volta nella foto e mostrare raggruppati a lato solo film in cui ha con Linda
non so se mi sono spiegato

ecco il codice

PHP:
$actor_id = $_GET["id"];

//......id prelevato tramite get: $id=_GET['id'];
// questa query visualizza i film con cui ha lavorato l'attore
$query = "select actor_id, film_id,
  (select nome from actor a where a.actor_id = am.actor_id) as nome,
  (select foto from actor  a where a.actor_id = am.actor_id) as foto,
  (select movie_title from film  a where a.film_id = am.film_id) as movie_title,
  (select year from film a where a.film_id = am.film_id) as year,
 
  (select credited from film a where a.film_id = am.film_id) as credited,
  count(*) as film
from film_actor am
where film_id in (select film_id from film_actor where actor_id = $actor_id)
and actor_id <> $actor_id
group by actor_id, film_id
order by year DESC";

cgrlV6g.png
 
Ciao,
Mi sono permesso di ipotizzare come è fatto il tuo db (usato come base MySQL 5.6, non ho messo tutti i capi alla fine è per svolgere un esempio), ti ho fatto qualche esempio di come farei io le query: http://sqlfiddle.com/#!9/249d18/23
Se vedi puoi anche cliccare su "view execution plan" che ti fa vedere cosa esegue il db per risolvere le query che ti ho proposto. Ti suggerisco di guardarlo per farti un'idea più chiara, qui un articolo carino che spiega come leggerlo.

In questo caso secondo me è meglio usare le join, leggi meglio il testo della qeury e fai meno richieste al db.

Nell'esempio, in cima all'editor SQL vedi un SET @cur_act_id = 1; quello indicherebbe il tuo $actor_id = $_GET["id"];

Te le riassumo velocemente (al fine di spiegarmi, simulo di star eseguendo la query per Linda Blair):
La prima che ti propongo, quella senza group by per capirci, è simile alla tua, avrai una riga per ogni attore e per ogni film con cui Linda Blair ha partecipato , quindi dato che ha collaborato con Max Von Sydow in 2 film, Max Von Sydow apparirà 2 volte (una per ogni film). La grande differenza con la tua è che qui vengono usate le join, quindi come dicevo sopra è più leggibile, meno richieste ecc ecc...

Puoi lato codice effettuare un raggruppamento con una cosa simile:
PHP:
[...]
$result_set = mysqli_query($conn, $sql);

// construct an associative array
$result = array();
while($row = mysqli_fetch_assoc($result_set)){
    $v[$row['actor_id']] = $row;
}

[...]

Questo ti permette di avere in $result una cosa simile:
PHP:
// struttura array per $result, le stringhe in maisuc rappresentano i valori presi dal db
array(
    ID_ATTORE => array(
        'id' => ID_ATTORE,
        'name' => NOME_ATTORE,
        'film' => TITOLO_FILM,
        'year' => ANNO,
    )
)

In questo modo puoi gestire più efficacemente l'impaginazione che vorrai mettere.
----
La seconda proposta è molto simile alla prima, l'unica differenza è che viene usato il group by, e la funzione GROUP_CONCAT che concatena i risultati raggruppati. In questo caso avrai una riga per ogni attore che ha collaborato con Linda Blair, con i film che li accomunano raggruppati con la funzione GROUP_CONCAT.

Questa risponde perfettamente alla tua domanda, ed è utile nel caso tu sappia già come impaginare i risultati puoi giocare con i separatori delle funzioni CONCAT() e GROUP_CONCAT() per farti uscire il campo e stamparlo direttamente così come te lo torna il db.

----

Ti ho messo anche la tua (cambiando qualche nome di colonna, come ti dicevo non ho messo tutti i campi alla fine è solo un test) per farti fare un confronto.

Ultima attenzione, ma molto importante, attento quando usi un input esterno $actor_id = $_GET["id"]; per una query, come hai scritto tu sei a rischio di SQL Injection! Valida sempre gli input e usa le apposite funzione che php ti fornisce ad esempio il prepare di mysqli (qui maggiori info)


Sono stato un po' lungo, ma spero di essere stato chiaro e di averti aiutato, in caso contrario fammi sapere ;)
 
Ciao f107
grazie per la risposta :)

devo specificare che non sono un programmatore (il mio lavoro e' ben diverso) il php e' solo un modo per imparare un linguaggio, quindi perdonami se la maggior parte delle cose che per te sono scontate per me sono nuove :(

Si, utilizzo MySQL 5.6 e il tutto lavora in localhost (quindi non mi preoccupa SQL injection), il database che sto cercando di costruire e' per uso privato e non verra' mai rilasciato online.

Ho visto la tua query in azione e ho provato a togliere il mio codice e inserire l'altro per un test

risultato

Parse error[/B]: syntax error, unexpected '@' in [B]E:\OSPanel\domains\localhost\cinema\credited_with.php[/B] on line [B]74

linea 74 SET @cur_act_id = 1;

ti allego la pagina php originale che ho per aver meglio un'idea

Grazie
 
Ultima modifica:
  • Like
Reactions: f107
schema (semplificato) database

Table -> actor
actor_id
nome
Table-> film
film_id
movie_title
Table-> film_actor
actor_id
film_id

0Ldtpcd.png
 
Ciao @Alex_70 ,
Scusami se ho dato qualcosa per scontato, ma data la tua voglia di imparare spero tu abbia degli spunti validi con la mia risposta.

Anche se lavori in localhost, questo è solo un consiglio, fai sempre attenzione a quello che scrivi, un domani potresti pubblicarlo per prova, penso sia meglio prendere come abitudine la scrittura di un codice sicuro.

@Tommy03 ha ragione, scusami ti avevo lasciato quel @cur_act_id solo per provare diversi id con quel tool che ti avevo linkato, senza dover cambiare a mano per ogni query.
Nell'esempio, in cima all'editor SQL vedi un SET @cur_act_id = 1; quello indicherebbe il tuo $actor_id = $_GET["id"];


Ho dato una veloce occhiata al codice che hai messo (la prossima volta mettilo qui con i tag code), mi pare di vedere che hai copiato e incollato insieme tutte e 3 le query che avevo scritto come se fossero istruzioni PHP, quelle sono query, devi scegliere quella che fa al caso tuo e sostituirla tipo così:

PHP:
// siamo sicuri che l'id debba essere un intero, con intval siamo un poco più tranquilli
$actor_id = intval($_GET["id"]);

//......id prelevato tramite get: $id=_GET['id'];
// questa query visualizza i film con cui ha lavorato l'attore
$query = "
SELECT 
  `a`.`actor_id`, 
  `a`.`nome`,
  `a`.`foto`,
  GROUP_CONCAT(CONCAT(`f`.`film_id`, ' || ', `f`.`movie_title`, ' || ', `f`.`year`, '||', `f`.`credited`)) as films
FROM 
  `film_actor` `sel_act`
INNER JOIN `film_actor` `other_act` ON 
  `other_act`.`film_id` = `sel_act`.`film_id`
  AND `other_act`.`actor_id` != `sel_act`.`actor_id` 
INNER JOIN `actor` `a` ON 
  `a`.`actor_id` = `other_act`.`actor_id`
INNER JOIN `film` `f` ON 
  `f`.`film_id` = `other_act`.`film_id`
WHERE
  `sel_act`.`actor_id` = $actor_id

GROUP BY `a`.`actor_id`, `a`.`name`
ORDER BY `f`.`year` DESC;
";

Controlla bene i nomi delle colonne nella select qui sopra se sono corretti, puoi aggiungere o togliere quello che vuoi.

Facci sapere se riesci
 
Ciao f107 :) ,
ti ringrazio per la tua disponibilita' ad aiutarmi, naturalmente sono accettati aiuti da chiunque

per la query ci sono arrivato poi, prima pensavo che era unica, comunque ho inserito quella modificata sopra e..

mySQL error: Unknown column 'f.credited' in 'field list'

:oops: adesso non capisco

ho provato ad aggiungere credited a select ma il risultato non cambia

PHP:
$query = "
SELECT
  `a`.`actor_id`,
  `a`.`nome`,
  `a`.`foto`,
`a`.`credited`,
 
Ultima modifica:
Di nulla :)
credited è una colonna di quale tabella? Io ho pensato, sicuramente erroneamente, che fosse di film, quindi ho usato `f`.`credited`.
a seconda della tua risposta devi cambiare il il riferimento dell'alias per la colonna credited qui:
GROUP_CONCAT(CONCAT(`f`.`film_id`, ' || ', `f`.`movie_title`, ' || ', `f`.`year`, '||', `f`.`credited`)) as films
se è di actor metti `a`.`credited`
se è di film metti `f`.`credited`
se è di film_actor metti `other_act`.`credited`
 
dunque credited si trova nella tabella che collega actor e film, cioe' film_actor

ho messo questo

Codice:
[CODE=php]GROUP_CONCAT(CONCAT(`f`.`film_id`, ' || ', `f`.`movie_title`, ' || ', `f`.`year`, '||', `other_act`.`credited`)) as films

e corretto questo campo

name

PHP:
GROUP BY `a`.`actor_id`, `a`.`nome`

risultato e che non visualizzo
il credited sotto il nome
year
e i film a lato

group_actor_film_2.png
 
Ultima modifica:
Sono molto contento che hai fatto delle prove e che stai provando a capire! Grande!

Se aggiungi i campi così, a causa del group by, avrai un solo valore di ritorno per quelle colonne, devi necessariamente aggiornare il tuo codice che impagina i risultati (quello dentro il blocco while per capirci), con la query che hai scelto, i valori aggregati dei film per ogni attore è dato da questo: GROUP_CONCAT(CONCAT(`f`.`film_id`, ' || ', `f`.`movie_title`, ' || ', `f`.`year`, '||', `other_act`.`credited`)) as films Quindi dentro la "colonna" films che ti ritorna la query hai i valori aggregati che puoi manipolare.

Suggerimento, se ti fai un var_dump della variabile $row ti vedi che dati ci sono dentro.
Vorrei evitare di darti la soluzione già pronta, se leggi meglio (anche nella mia prima risposta ti avevo dato abbastanza info) e fai qualche prova sicuramente riesci ;)
 
forse ti riferisci a questo?

cambiato


PHP:
$result_set = mysql_query($query);


// construct an associative array

$result = array();

while($row = mysql_fetch_assoc($result_set)){

$v[$row['actor_id']] = $row;

}

 


?>


e mi da errore :confused:


PHP:
Parse error[/B]: syntax error, unexpected 'endwhile' (T_ENDWHILE) in [B]E:\OSPanel\domains\localhost\cinema\credited_with.php[/B] on line [B]132

linea 132

PHP:
<? endwhile; ?>
 
Ultima modifica:
niente, non riesco a capire come strutturare il while :(

purtroppo ho ancora dei limiti con il php
 
@Alex_70
Da regolamento del forum, come tutti noi sei tenuto ad usare il tag
PHP (2).png
quando posti del codice php, oppure la funzione codice dalla barra degli strumenti
box inserisci.png

Inoltre IMPORTANTE: Prima di creare una nuova discussione o di rispondere alle discussioni esistenti ricordati di leggere attentamente il Regolamento del Forum e l'eventuale regolamento specifico della sezione!
Grazie


Correggi i tuoi post in questo modo altrimenti elimino la discussione
 

Discussioni simili