MySQL 使用 JOIN 查找或使用 TEMPORARY 的相关子查询 TABLE
MySQL lookup using JOIN or correlated subquery with TEMPORARY TABLE
我有两个主要的 tables,providers’ and
depots`。每个提供者都有一个强制性的第一个位置。通过添加额外的 'depot' 来提供额外的位置。 'etc' 表示与提供商帐户相关的大量附加变量。为了简化起见,此处省略了额外的 table 信息和过滤器。
providers
+--------+------------+-----+
| id | location | etc |
+--------+------------+-----+
| 1 | POINT(1,1) | ... |
| 2 | POINT(1,2) | ... |
| 3 | POINT(1,3) | ... |
+--------+------------+-----+
depots
+---------+------------+------------+
| depotId | providerId | location |
+---------+------------+------------+
| 1 | 1 | POINT(2,1) |
| 2 | 1 | POINT(2,2) |
| 3 | 1 | POINT(2,3) |
| 4 | 2 | POINT(2,4) |
| 5 | 2 | POINT(2,5) |
+---------+------------+------------+
提供商可能有零个或多个附加软件仓库。这些 'locations' 用于计算来自每个提供商的传入“工作”的距离。传统上我使用 UNION 连接 providers
和 depots
table 形成一个 table,我将其称为 provDeps
.
SELECT id, location, 0 AS depotId FROM providers
UNION SELECT p.id, d.location d.id AS depotId FROM providers p, depots d
让我们假设这是一个视图,暂时放弃效率和索引。它有望降低查询的视觉复杂性。
provDeps
+--------+------------+---------+-----+
| id | location | depotId | etc |
+--------+------------+---------+-----+
| 1 | POINT(1,1) | 0 | ... |
| 1 | POINT(2,1) | 1 | ... |
| 1 | POINT(2,2) | 2 | ... |
| 1 | POINT(2,3) | 3 | ... |
| 2 | POINT(1,2) | 0 | ... |
| 2 | POINT(2,4) | 4 | ... |
| 2 | POINT(2,5) | 5 | ... |
| 3 | POINT(1,3) | 0 | ... |
+--------+------------+---------+-----+
然后我使用 provDeps
执行额外的查找。这里的想法是计算作业到每个站点的距离。这是通过存储过程执行的。
SELECT loc.*, degToMeter(st_distance(jobLocation, location)) AS distanceToJob FROM provDeps;
+--------+------------+---------+---------------+-----+
| id | location | depotId | distanceToJob | etc |
+--------+------------+---------+---------------+-----+
| 1 | POINT(1,1) | 0 | 8234 | ... |
| 1 | POINT(2,1) | 1 | 7334 | ... |
| 1 | POINT(2,2) | 2 | 6434 | ... |
| 1 | POINT(2,3) | 3 | 5534 | ... |
| 2 | POINT(1,2) | 0 | 4634 | ... |
| 2 | POINT(2,4) | 4 | 3734 | ... |
| 2 | POINT(2,5) | 5 | 2834 | ... |
| 3 | POINT(1,3) | 0 | 1934 | ... |
+--------+------------+---------+---------------+-----+
我现在需要减少这个列表,只保留最近的仓库,按供应商 ID 分组。结果将包括每个提供者,但每个提供者只有一个站点 - 主要位置、站点“0”或最近的站点的 ID。这是期望的结果:-
+--------+------------+---------+---------------+-----+
| id | location | depotId | distanceToJob | etc |
+--------+------------+---------+---------------+-----+
| 1 | POINT(2,3) | 3 | 5534 | ... |
| 2 | POINT(2,5) | 5 | 2834 | ... |
| 3 | POINT(1,3) | 0 | 1934 | ... |
+--------+------------+---------+---------------+-----+
我尝试了多种方法,但每种方法都遇到了不同的问题。我最接近成功的方法是使用临时 table :-
DROP TEMPORARY TABLE IF EXISTS locTemp;
CREATE TEMPORARY TABLE locTemp AS
SELECT depots.*, st_distance(jobLocation, location) AS distanceToJob
FROM provDeps
然后我尝试使用相关子查询,但这会产生关于在一次查找中尝试访问临时 table 两次的错误:-
SELECT * FROM locTemp
WHERE distanceToJob = (SELECT MIN(distanceToJob) FROM locTemp AS lt WHERE lt.id = locTemp.id);
这会导致错误 "Can't reopen table: 'locTemp'"。我也尝试过执行连接,但随后出现分组错误,或者无法从子查询中访问临时 table 本身:-
SELECT * FROM
(
SELECT id, depotId, MIN(distanceToJob) as minDist
FROM locTemp GROUP BY id
) AS res
INNER JOIN locTemp AS lt on lt.id = res.id and lt.minDist = res.distanceToJob;
任何指点,或更好的解决方案,将不胜感激! :)
我认为您不一定需要临时 table 或查看此处。您的最终查询在这里看起来完全正常,我在下面对其进行了修改。我看到的唯一问题是您 select 一个非聚合列 GROUP BY
并且使用临时 table.
可能存在问题
SELECT
t1.id, t1.location, t1.depotId,
degToMeter(st_distance(t1.jobLocation, t1.location)) AS distanceToJob
FROM provDeps t1
INNER JOIN
(
SELECT
id,
MIN(degToMeter(st_distance(t1.jobLocation, t1.location))) AS minDistanceToJob
FROM provDeps
GROUP BY id
) t2
ON t1.id = t2.id AND
degToMeter(st_distance(t1.jobLocation, t1.location)) = t2.minDistanceToJob;
我有两个主要的 tables,providers’ and
depots`。每个提供者都有一个强制性的第一个位置。通过添加额外的 'depot' 来提供额外的位置。 'etc' 表示与提供商帐户相关的大量附加变量。为了简化起见,此处省略了额外的 table 信息和过滤器。
providers
+--------+------------+-----+
| id | location | etc |
+--------+------------+-----+
| 1 | POINT(1,1) | ... |
| 2 | POINT(1,2) | ... |
| 3 | POINT(1,3) | ... |
+--------+------------+-----+
depots
+---------+------------+------------+
| depotId | providerId | location |
+---------+------------+------------+
| 1 | 1 | POINT(2,1) |
| 2 | 1 | POINT(2,2) |
| 3 | 1 | POINT(2,3) |
| 4 | 2 | POINT(2,4) |
| 5 | 2 | POINT(2,5) |
+---------+------------+------------+
提供商可能有零个或多个附加软件仓库。这些 'locations' 用于计算来自每个提供商的传入“工作”的距离。传统上我使用 UNION 连接 providers
和 depots
table 形成一个 table,我将其称为 provDeps
.
SELECT id, location, 0 AS depotId FROM providers UNION SELECT p.id, d.location d.id AS depotId FROM providers p, depots d
让我们假设这是一个视图,暂时放弃效率和索引。它有望降低查询的视觉复杂性。
provDeps
+--------+------------+---------+-----+
| id | location | depotId | etc |
+--------+------------+---------+-----+
| 1 | POINT(1,1) | 0 | ... |
| 1 | POINT(2,1) | 1 | ... |
| 1 | POINT(2,2) | 2 | ... |
| 1 | POINT(2,3) | 3 | ... |
| 2 | POINT(1,2) | 0 | ... |
| 2 | POINT(2,4) | 4 | ... |
| 2 | POINT(2,5) | 5 | ... |
| 3 | POINT(1,3) | 0 | ... |
+--------+------------+---------+-----+
然后我使用 provDeps
执行额外的查找。这里的想法是计算作业到每个站点的距离。这是通过存储过程执行的。
SELECT loc.*, degToMeter(st_distance(jobLocation, location)) AS distanceToJob FROM provDeps;
+--------+------------+---------+---------------+-----+
| id | location | depotId | distanceToJob | etc |
+--------+------------+---------+---------------+-----+
| 1 | POINT(1,1) | 0 | 8234 | ... |
| 1 | POINT(2,1) | 1 | 7334 | ... |
| 1 | POINT(2,2) | 2 | 6434 | ... |
| 1 | POINT(2,3) | 3 | 5534 | ... |
| 2 | POINT(1,2) | 0 | 4634 | ... |
| 2 | POINT(2,4) | 4 | 3734 | ... |
| 2 | POINT(2,5) | 5 | 2834 | ... |
| 3 | POINT(1,3) | 0 | 1934 | ... |
+--------+------------+---------+---------------+-----+
我现在需要减少这个列表,只保留最近的仓库,按供应商 ID 分组。结果将包括每个提供者,但每个提供者只有一个站点 - 主要位置、站点“0”或最近的站点的 ID。这是期望的结果:-
+--------+------------+---------+---------------+-----+
| id | location | depotId | distanceToJob | etc |
+--------+------------+---------+---------------+-----+
| 1 | POINT(2,3) | 3 | 5534 | ... |
| 2 | POINT(2,5) | 5 | 2834 | ... |
| 3 | POINT(1,3) | 0 | 1934 | ... |
+--------+------------+---------+---------------+-----+
我尝试了多种方法,但每种方法都遇到了不同的问题。我最接近成功的方法是使用临时 table :-
DROP TEMPORARY TABLE IF EXISTS locTemp;
CREATE TEMPORARY TABLE locTemp AS
SELECT depots.*, st_distance(jobLocation, location) AS distanceToJob
FROM provDeps
然后我尝试使用相关子查询,但这会产生关于在一次查找中尝试访问临时 table 两次的错误:-
SELECT * FROM locTemp
WHERE distanceToJob = (SELECT MIN(distanceToJob) FROM locTemp AS lt WHERE lt.id = locTemp.id);
这会导致错误 "Can't reopen table: 'locTemp'"。我也尝试过执行连接,但随后出现分组错误,或者无法从子查询中访问临时 table 本身:-
SELECT * FROM
(
SELECT id, depotId, MIN(distanceToJob) as minDist
FROM locTemp GROUP BY id
) AS res
INNER JOIN locTemp AS lt on lt.id = res.id and lt.minDist = res.distanceToJob;
任何指点,或更好的解决方案,将不胜感激! :)
我认为您不一定需要临时 table 或查看此处。您的最终查询在这里看起来完全正常,我在下面对其进行了修改。我看到的唯一问题是您 select 一个非聚合列 GROUP BY
并且使用临时 table.
SELECT
t1.id, t1.location, t1.depotId,
degToMeter(st_distance(t1.jobLocation, t1.location)) AS distanceToJob
FROM provDeps t1
INNER JOIN
(
SELECT
id,
MIN(degToMeter(st_distance(t1.jobLocation, t1.location))) AS minDistanceToJob
FROM provDeps
GROUP BY id
) t2
ON t1.id = t2.id AND
degToMeter(st_distance(t1.jobLocation, t1.location)) = t2.minDistanceToJob;