简体   繁体   中英

MySQL INNER join with RIGHT join and multiple conditional WHERE clause with FULL TEXT

I have three tables:

Meta
Posters
Tags

Posters has a many-to-one relationship on id to Meta. Tags has a many-to-one relationship on poster_id to Posters.

Meta <-- many-to-one Posters <-- many-to-one Tags

so a Meta item can have many posters, and a poster can have many tags.

I am trying to create a SINGLE query that can accept conditional filters including specific Tag types.

function get_filter_posters($filters, $start) {
      $query = "SELECT Meta.id, Meta.year, Posters.id AS poster_id, Posters.filename, Meta.imp_title
                FROM Meta INNER JOIN Posters ON Meta.id = Posters.movie_id
                RIGHT JOIN Tags ON Posters.id = Tags.poster_id
                WHERE Meta.year >= :lower
                AND Meta.year <= :upper ";

      foreach ($filters["genre"] as $key => $value) {
        if($value){ $query .= " AND Meta.genre = '".$key."' "; }
      }

      foreach ($filters["style"] as $key => $value) {
        if($value){ $query .= " AND Tags.tag = '".$key."' "; }
      }

      $query .= "ORDER BY Meta.year DESC
                 LIMIT :start,:limit";

      $statement = $this->db->prepare($query);
      $statement->bindParam(':limit', $this->limit, PDO::PARAM_INT);
      $statement->bindParam(':start', $start, PDO::PARAM_INT);
      $statement->bindParam(':lower', $filters["year_range"][0], PDO::PARAM_INT);
      $statement->bindParam(':upper', $filters["year_range"][1], PDO::PARAM_INT);
      $statement->execute();
      return $statement->fetchAll(PDO::FETCH_ASSOC);
 }

this works only when a SINGLE style element is true. If more than one style element is found to be true, and therefore an additional where clause is added:

      foreach ($filters["style"] as $key => $value) {
        if($value){ $query .= " AND Tags.tag = '".$key."' "; }
      }

then the query always returns an empty set when there is in fact a single poster with multiple tags.

if a query is written with just a single style element set to true, then the query returns proper posters. More than one, ALWAYS returns empty, which is not the case.

also this will be extended with a TEXT search as well. This one dosnt work at all as expected.

$query = "SELECT Meta.id, Meta.year, Posters.id AS poster_id, Posters.filename, Meta.imp_title,
              MATCH(".$search_type.") AGAINST($term) AS Relevance
              FROM Meta INNER JOIN Posters ON Meta.id = Posters.movie_id
              RIGHT JOIN Tags ON Posters.id = Tags.poster_id
              WHERE MATCH(".$search_type.")
              AGAINST($term IN BOOLEAN MODE)";

      foreach ($filters["genre"] as $key => $value) {
        if($value){ $query .= " AND Meta.genre = '".$key."' "; }
      }

      foreach ($filters["style"] as $key => $value) {
        if($value){ $query .= " AND Tags.tag = '".$key."' "; }
      }

      $query .= "AND Meta.year >= ".$filters["year_range"][0]."
                 AND Meta.year <= ".$filters["year_range"][1]."
                 ORDER BY Relevance + Meta.year DESC
                 LIMIT :start,:limit";

      $statement = $this->db->prepare($query);
      $statement->bindParam(':start', $start, PDO::PARAM_INT);
      $statement->bindParam(':limit', $this->limit, PDO::PARAM_INT);
      $statement->execute();
      return $statement->fetchAll(PDO::FETCH_ASSOC);

disregard the fact that i didnt bindParam the filter years - it will be done

Maybe i am approaching this in an incorrect way? If so, any advice would greatly help

THANK YOU!

The right join is being negated by the where clause meta.year statement. Thus if a tag exists, without posters or meta data, it is being EXCLUDED (the right join in essence is being treated as a INNER JOIN). To correct, you would need to make the where clause limits on meta part of the join either at the posters level or the tag right join...

perhaps

  $query = "SELECT Meta.id, Meta.year, Posters.id AS poster_id, Posters.filename, Meta.imp_title
            FROM Meta 
            INNER JOIN Posters ON Meta.id = Posters.movie_id
            RIGHT JOIN Tags ON Posters.id = Tags.poster_id
             ON Meta.year >= :lower
            AND Meta.year <= :upper ";

or

  $query = "SELECT Meta.id, Meta.year, Posters.id AS poster_id, Posters.filename, Meta.imp_title
            FROM Meta INNER JOIN Posters 
              ON Meta.id = Posters.movie_id
             AND Meta.year >= :lower
             AND Meta.year <= :upper
            RIGHT JOIN Tags ON Posters.id = Tags.poster_id";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM