简体   繁体   中英

MySQL Select Inner Join (Only Unique)

In my app, I have vehicles which are assigned to a specific class. In the query below I am trying to select all classes which have at least one vehicle in it that is in a certain area.

The code below works fine, however if there are multiple vehicles inside of the class that fit the location parameter, multiple instances of the class are returned in the results.

How can I structure this query so only one instance of every class is returned, regardless of how many vehicles inside of the class fit the paramater?

$get_veh = $pdo->prepare("SELECT * FROM tbl_car_class_category JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69) and (:loc_long+:radius/cos(radians(:loc_lat))*69) and veh_advanceLat between (:loc_lat-(:radius/69)) and (:loc_lat+(:radius/69)) AND veh_status=:veh_status");

$get_veh->bindparam(":veh_status", $veh_status);
$get_veh->bindparam(":loc_lat", $loc_lat);
$get_veh->bindparam(":loc_long", $loc_long);
$get_veh->bindparam(":radius", $radius);

$get_veh->execute();

If the intent is return just rows from the category table, we could replace the JOIN with an EXISTS (correlated subquery)

For example:

 SELECT c.*
   FROM tbl_car_class_category c
  WHERE EXISTS
      ( SELECT 1 
          FROM tbl_vehicles v 
         WHERE v.veh_class_id = c.id_class_cat
           AND v.veh_advanceLng 
               BETWEEN (:loc_long-:radius/cos(radians(:loc_lat))*69)
                   AND (:loc_long+:radius/cos(radians(:loc_lat))*69)
           AND v.veh_advanceLat
               BETWEEN (:loc_lat-(:radius/69)) 
                   AND (:loc_lat+(:radius/69))
           AND v.veh_status=:veh_status
      )

If we also need to return a row from the vehicle table, we can use aggregation in an inline view, and a JOIN .

 SELECT c.*
      , g.*
   FROM tbl_car_class_category c
   JOIN ( SELECT v.veh_class_id
               , MIN(v.id)    AS   min_id   -- PK or unique identifier    
            FROM tbl_vehicles v 
            AND v.veh_advanceLng 
                BETWEEN (:loc_long-:radius/cos(radians(:loc_lat))*69)
                    AND (:loc_long+:radius/cos(radians(:loc_lat))*69)
            AND v.veh_advanceLat
                BETWEEN (:loc_lat-(:radius/69)) 
                    AND (:loc_lat+(:radius/69))
            AND v.veh_status=:veh_status
          GROUP BY v.veh_class_id 
        ) m
     ON m.veh_class_id = c.id_class_cat
   JOIN tbl_vehicles g
     ON g.id           = m.min_id
    AND g.veh_class_id = m.veh_class_id
  ORDER BY ...

(NOTE: this assumes that id_class_cat is UNIQUE in tbl_car_class_category )

Have you tried LIMIT?

$get_veh = $pdo->prepare("SELECT * FROM tbl_car_class_category JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69) and (:loc_long+:radius/cos(radians(:loc_lat))*69) and veh_advanceLat between (:loc_lat-(:radius/69)) and (:loc_lat+(:radius/69)) AND veh_status=:veh_status LIMIT 1");

http://www.mysqltutorial.org/mysql-limit.aspx

Or DISTINCT: https://dev.mysql.com/doc/refman/5.7/en/distinct-optimization.html

for get a single row for each class you can use a (fake eg: min) aggregation functio and group by

( do the absence of the table schema assuming that you have col1, col2, col3 instead of * )

$get_veh = $pdo->prepare("SELECT 
               tbl_car_class_category.id_class_cat
                    , min(col1)
                    , min(col2) 
                    , min(col3)
     FROM tbl_car_class_category 
     JOIN tbl_vehicles ON tbl_vehicles.veh_class_id = tbl_car_class_category.id_class_cat
     WHERE tbl_vehicles.veh_advanceLng between (:loc_long-:radius/cos(radians(:loc_lat))*69) 
                    and (:loc_long+:radius/cos(radians(:loc_lat))*69) 
                    and veh_advanceLat between (:loc_lat-(:radius/69)) 
                    and (:loc_lat+(:radius/69)) AND veh_status=:veh_status
                    GROUP BY tbl_car_class_category.id_class_cat");

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