这个超出了我的SQL能力。我有一个查询,选择具有一定半径的对象的所有对象,它完美地工作。它首先创建一个边界框以获取所有潜在候选者,然后从该边界框内计算半径以选择结果。
SELECT *
FROM (
SELECT b.*, pr.postcode, pr.prize, pr.title, pr.collection, pr.redeemed, pr.delivery, pr.archived, bt.category, b.id as objectid, b.updated as changed,
p.radius,
p.distance_unit
* DEGREES(ACOS(COS(RADIANS(p.latpoint))
* COS(RADIANS(b.lat))
* COS(RADIANS(p.longpoint - b.lng))
+ SIN(RADIANS(p.latpoint))
* SIN(RADIANS(b.lat))))
AS distance
FROM bubbles AS b, bubble_prizes AS pr, bubble_types AS bt
JOIN (
SELECT ? AS latpoint, ? AS longpoint,
? AS radius, ? AS distance_unit
) AS p
WHERE pr.bubble = b.id
AND b.deleted = 0
AND b.type IN ($placeholders)
AND b.type = bt.type
AND b.updated > $since
AND b.lat
BETWEEN p.latpoint - (p.radius / p.distance_unit)
AND p.latpoint + (p.radius / p.distance_unit)
AND b.lng
BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
) AS d
WHERE distance <= radius
ORDER BY distance";
(此查询源自本文http://www.movable-type.co.uk/scripts/latlong-db.html)
我的问题是,现在我想修改它,以便选择所有
的对象b.created = userid或b.catch_held = userid或[对象在某个点的某个半径范围内(如上所述)]
它还需要高效。也就是说,在b.created = userid或b.catch_held = userid的情况下,我不想计算DISTANCE或进行任何边界框计算,我不知道如何重构查询实现这一目标。
请注意,无论create或catct_held如何,无距离相关的条件都需要保留。那是
pr.bubble = b.id
AND b.deleted = 0
AND b.type IN ($placeholders)
AND b.type = bt.type
AND b.updated > $since
有人可以帮忙吗?
答案 0 :(得分:2)
首先,您应该仅使用显式join
语法重写查询。一个简单的规则:永远不要在from
子句中使用逗号。
您正在寻找效率,因此基本上有两种方法。一种是保持查询不变,并使用union
引入其他行。另一种是修改查询。为此,只需在内部查询和外部查询中添加条件。这些都是简单的条件,所以不是那么难。
我对“距离”相关条件的含义有点模糊。以下假设所有非连接条件都与距离相关:
SELECT *
FROM (SELECT b.*, pr.postcode, pr.prize, pr.title, pr.collection, pr.redeemed, pr.delivery,
pr.archived, bt.category, b.id as objectid, b.updated as changed,
p.radius,
(p.distance_unit
* DEGREES(ACOS(COS(RADIANS(p.latpoint))
* COS(RADIANS(b.lat))
* COS(RADIANS(p.longpoint - b.lng))
+ SIN(RADIANS(p.latpoint))
* SIN(RADIANS(b.lat))))
) AS distance
FROM bubbles b JOIN
bubble_prizes pr
ON pr.bubble = b.id JOIN
bubble_types bt
ON b.type = bt.type CROSS JOIN
(SELECT ? AS latpoint, ? AS longpoint, ? AS radius, ? AS distance_unit
) p
WHERE (b.deleted = 0 AND
b.type IN ($placeholders) AND
b.updated > $since AND
b.lat BETWEEN p.latpoint - (p.radius / p.distance_unit) AND p.latpoint + (p.radius / p.distance_unit) AND
b.lng BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint)))) AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
) or
(b.created = userid OR b.catch_held = userid)
) b
WHERE distance <= radius or b.created = userid OR b.catch_held = userid
ORDER BY distance;
如果它不是你想要的,那么它应该足够接近。