【问题标题】:How to make a bi-table MYSQL select query based on longitude, latitude and radius?如何根据经度、纬度和半径进行双表MYSQL选择查询?
【发布时间】:2018-02-27 16:18:25
【问题描述】:

我有 2 张桌子。工人表和工作表。工作表接受latitudelongitudework radius。作业表有latitudelongitude。我需要一个从工作表中获取行的选择查询,但在工作表的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");

【问题讨论】:

  • 您确定您使用的是 MySQL? MySQL 通常不支持引用的表名和列。除非 MySQL 在其 sql-mode 中添加了“ANSI”。
  • 是的,我正在使用 MYSQL,显然,我的服务器支持它。 :)
  • 简单地说,根据他当前的坐标和他的允许范围找到他所在领域的工人的所有可用工作

标签: php mysql


【解决方案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);  

【讨论】:

  • 感谢您的回答,但是,这适用于所有工人和工作。我一次只需要为一名工人做这件事。因此,在 $result 中需要通过 ID 选择一名工人,然后根据该工人的位置和工作半径匹配工作。
  • 这也适用于单人,只需传递工人的 id,因此它将只选择一名工人并仅为该工人找到工作。 $result = $conn-&gt;query("SELECT * FROM worker where id=$worker_id");
  • 如何让它接受另一个参数。例如:FROM jobs WHERE something IN (:something) having distance &lt; :work_radius
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-15
  • 2014-01-21
  • 2010-12-16
  • 1970-01-01
相关资源
最近更新 更多