2014-10-05 2 views
1

이것은 SQL에서의 능력을 넘어서는 것입니다. 완벽하게 작동하는 객체의 특정 반경을 가진 모든 객체를 선택하는 쿼리가 있습니다. 먼저 경계 상자를 만들어 모든 잠재적 후보를 가져온 다음 해당 경계 상자 내에서 반경을 계산하여 결과를 선택합니다. 이 모든 객체복잡한 SQL 표현식을 최적화하십시오.

b.created = 사용자 ID 또는 B를 선택하도록

 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에서 파생 된) .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 

누군가가 도와 줄 수 있습니까?

답변

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; 

: 다음은 모든 비 가입 조건이 거리 관련 있다고 가정합니다.

+0

고든에게 감사드립니다. 이것은 내가 시도한 여러 가지 문제와 동일한 문제를 겪고 있는데, 그 이유는 b가 존재하지 않는 것 같고 당신이 얻는 것입니다 : 'where 절'에 알 수없는 열 'b.creator'가 있습니다. 지난 거리 <= radius보다 OR 문을 제거하면 구문 분석은되지만 작동하지 않습니다. – mark

+0

죄송합니다. b.creator는 위의 오류에서 b.creator가 아닙니다 ... – mark

+0

@mark. . . 외부 질의의 별칭은'b'가 아닌'd'이므로 외부 참조 용으로 사용해야합니다. –

관련 문제