如何基于经度,纬度和半径制作双表MYSQL选择查询?

时间:2018-02-27 16:18:25

标签: php mysql

我有2张桌子。工人桌和工作表。工作人员表接受latitudelongitudework radius。作业表包含latitudelongitude。我需要一个select查询来获取jobs表中的行,但是在worker表的work radius内。

下面是表格的结构和我到目前为止的内容,即从基于纬度和经度的表格中进行选择。

感谢您的帮助。

工人表:

CREATE TABLE "worker" (
  "id" varchar(25) NOT NULL,
  "latitude" varchar(25) NOT NULL,
  "longitude" varchar(25) NOT NULL,
  "work_radius" int(25) NOT NULL,
  "address" varchar(255) NOT NULL,
  PRIMARY KEY ("id")
);

工作表:

CREATE TABLE "jobs" (
  "id" varchar(25) NOT NULL,
  "latitude" varchar(25) NOT NULL,
  "longitude" varchar(25) NOT NULL,
  "address" varchar(255) NOT NULL,
  PRIMARY KEY ("id")
);

选择查询:

$jobs_load = $dbh->prepare("
SELECT
    `*`,
    (
        6371 *
        acos(
            cos( radians( :lat_id ) ) *
            cos( radians( `lat_id` ) ) *
            cos(
                radians( `long_id` ) - radians( :long_id )
            ) +
            sin(radians(:lat_id) *
            sin(radians(`lat_id`))
        )
    ) `work_radius`
FROM
    `jobs`
HAVING
    `work_radius` < :work_radius
ORDER BY
    `work_radius`
LIMIT
    25");

1 个答案:

答案 0 :(得分:1)

你需要遍历所有worker,然后为每个工作人员在其“范围”内找到工作,试试这个

$conn = $conn = new PDO("mysql:host=localhost;dbname=test", 'root', '');

$result = $conn->query("SELECT * FROM worker");

$allWorkers = [];

foreach($result as $row)
{
    $allWorkers[] = array(
                          'id'=> $row["id"],
                          'latitude'=>$row["latitude"], 
                          'longitude'=>$row["longitude"], 
                          'work_radius'=> $row["work_radius"] 
                    );
}



$distance_query = 'SELECT
  *, (
    6371 * acos (
      cos ( radians(:latitude) )
      * cos( radians( latitude) )
      * cos( radians( longitude ) - radians(:longitude) )
      + sin ( radians(:latitude) )
      * sin( radians( latitude) )
    )
  ) AS distance
FROM jobs
having distance < :work_radius
ORDER BY distance
LIMIT 0 , 20;';


$workers_jobs = array();

$stmt = $conn->prepare($distance_query);

foreach( $allWorkers as $worker)
{
    $stmt->bindParam(':latitude', $worker['latitude']);
    $stmt->bindParam(':longitude', $worker['longitude']);
    $stmt->bindParam(':work_radius', $worker['work_radius']);

    $stmt->execute();

    while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $workers_jobs[$worker['id']]['id'] = $row['id'];
        $workers_jobs[$worker['id']]['latitude'] = $row['latitude'];
        $workers_jobs[$worker['id']]['longitude'] = $row['longitude'];
    }

}

// $ workers_jobs每个工人和他的工作保持一行

<强>更新

假设您在作业表中有一个额外的列说“ Shift ”(varchar 50)

+----+-----------+-----------+---------+
| id | latitude  | longitude |  Shift  |
+----+-----------+-----------+---------+
|  1 | 51.919438 | 19.145136 | morning |
|  2 | 49.852276 | 15.015519 | evening |
|  3 | 49.208705 | 11.946989 | night   |
+----+-----------+-----------+---------+

如何在$distance_query中加入此内容? IN的绑定有点棘手,因此在进一步说明之前,您必须阅读this part

$conn = $conn = new PDO("mysql:host=localhost;dbname=test", 'root', '');

$result = $conn->query("SELECT * FROM worker");

$allWorkers = [];

foreach($result as $row)
{
    $allWorkers[] = array(
                          'id'=> $row["id"],
                          'latitude'=>$row["latitude"], 
                          'longitude'=>$row["longitude"], 
                          'work_radius'=> $row["work_radius"] 
                    );
}

    //** bind IN  - placeholders**//
    $shifts = ['morning','night'];
    $in = '';

    foreach ($shifts as $i => $item)
    {
        $key    =   ':shift'.$i;
        $in .= "$key,";
    }
    $in = rtrim($in, ',');
    //** bind IN - placeholders end **// 


$distance_query = 'SELECT
  *, (
    6371 * acos (
      cos ( radians(:latitude) )
      * cos( radians( latitude) )
      * cos( radians( longitude ) - radians(:longitude) )
      + sin ( radians(:latitude) )
      * sin( radians( latitude) )
    )
  ) AS distance
FROM jobs
 where shift IN (' . $in . ')
having distance < :work_radius
ORDER BY distance
LIMIT 0 , 20;';


$workers_jobs = array();

$stmt = $conn->prepare($distance_query);

foreach( $allWorkers as $worker)
{
    $stmt->bindParam(':latitude', $worker['latitude']);
    $stmt->bindParam(':longitude', $worker['longitude']);
    $stmt->bindParam(':work_radius', $worker['work_radius']);

    //** bind IN - values**//
    $shifts = ['morning','night'];
    $in = '';

    foreach ($shifts as $i => $item)
    {
        $key    =   ':shift'.$i;
        $stmt->bindParam($key, $item);
    }

    //** bind IN - values ends**// 


    $stmt->execute();

    while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $workers_jobs[$worker['id']]['id'] = $row['id'];
        $workers_jobs[$worker['id']]['latitude'] = $row['latitude'];
        $workers_jobs[$worker['id']]['longitude'] = $row['longitude'];
    }

}

echo '<pre>'; print_r($workers_jobs);