2011-02-17 55 views
3

嘿夥計們。我有一個相當笨拙的SQL查詢:MySQL子查詢重用

SELECT username, users.photo_url, fp, dp,users.vid, 
     GLength(LineStringFromWKB(LineString(AsBinary(PointFromText('POINT({$geolat} {$geolong})')), 
              AsBinary(location)))) AS distance 
    FROM users 
    INNER JOIN venues ON users.vid = venues.vid 
    LEFT JOIN deflects ON users.username = deflects.defender 
    WHERE username NOT LIKE '{$mysql['username']}' 
    AND username NOT LIKE '{$users['king']['username']}' 
    AND venues.location IS NOT NULL 
    HAVING 
    (distance <= (
     SELECT MAX(distance) AS max_distance 
     FROM (
      SELECT 
       GLength(LineStringFromWKB(LineString(AsBinary(PointFromText('POINT({$geolat} {$geolong})')), 
                AsBinary(location)))) 
       AS distance 
       FROM users 
       INNER JOIN venues ON users.vid = venues.vid 
       LEFT JOIN deflects ON users.username = deflects.defender 
       WHERE users.fp = 0 
       AND username NOT LIKE '{$mysql['username']}' 
       AND username NOT LIKE '{$users['king']['username']}' 
       AND venues.location IS NOT NULL 
       AND deflects.dp IS NULL 
       ORDER BY distance LIMIT 5 
     ) AS unfrozen) 
    OR vid = '{$vid}') 
    ORDER BY distance 

現在我再次使用了很多相同的查詢兩次 - 特別是我想避免這樣做,距離計算一次以上 - 但我想不出瞭解如何做到這一點。我使用MySQL,所以我不認爲公用表表達式是一種選擇。另外,我在臨時表中遇到了一些麻煩。有沒有辦法以這樣的方式對這個查詢進行短語,以便我可以重新使用距離計算?

另外,我知道我計算距離的方式並沒有給出給定的geolt,geolong的真實距離,但它足夠接近我的目的。

編輯:這裏 而且......是幾乎完全基於以下理查德的迴應我得到了什麼工作,:

SELECT username, distance, photo_url, vid, fp, dp 
    FROM (
    SELECT username, photo_url, vid, fp, dp, 
     @d := distance AS distance, 
     @c := if(fp = 0 
        AND dp IS NULL 
        AND @d>[email protected], @c+1, @c), 
     @max := if(fp = 0 
        AND dp IS NULL 
        AND @d>[email protected] 
        AND @c <= 5, @d, @max) 
    FROM (SELECT @max:=0, @d:=null, @c:=0) AS MaxTally 
     INNER JOIN (
      SELECT username, photo_url, users.vid, users.fp, deflects.dp, 
       GLength(LineStringFromWKB(LineString(AsBinary(PointFromText('POINT({$geolat} {$geolong})')), 
                 AsBinary(location)))) 
       AS distance 
      FROM users 
       INNER JOIN venues ON users.vid = venues.vid 
       LEFT JOIN deflects ON users.username = deflects.defender 
      WHERE username NOT LIKE '{$mysql['username']}' 
       AND username NOT LIKE '{$users['king']['username']}' 
       AND venues.location IS NOT NULL 
      ORDER BY distance 
     ) AllUsers 
) AllUsersWithMaxTally 
    WHERE vid = '{$vid}' OR distance <= @max 
    ORDER BY distance 

感謝理查德!

+0

緩存結果呢? – yoda 2011-02-17 06:34:12

+0

'按距離限制5'表示你只想要那些最接近5的MAX? – RichardTheKiwi 2011-02-17 06:53:52

回答

2

僞碼 - 如果需要的話我以後再修復代碼,但是這可能讓你開始足以讓答案自己。 MySQL允許你做瘋狂的事情!

SELECT 
    username, 
    distance 
FROM 
(
SELECT 
    username, 
    @d:=distance AS distance, 
    @c := if(fp = 0 
       AND dp IS NULL 
       AND @d>[email protected], @c+1, @c), 
    @max := if(fp = 0 
       AND dp IS NULL 
       AND @d>[email protected] 
       AND @c <= 5, @d, @max) MaxOf5Dist 
FROM (select @max:=-1000, @d:=null, @c:=0) M 
INNER JOIN (
SELECT 
    username, # others taken out for brevity 
    users.fp, deflects.dp, 
    GLength(LineStringFromWKB(LineString(AsBinary(
      PointFromText('POINT({$geolat} {$geolong})')), AsBinary(location)))) 
      AS distance 
FROM users 
CROSS JOIN venues ON users.vid = venues.vid 
LEFT JOIN deflects ON users.username = deflects.defender 
WHERE username NOT LIKE '{$mysql['username']}' 
    AND username NOT LIKE '{$users['king']['username']}' 
    AND venues.location IS NOT NULL 
ORDER BY distance 
) X 
) Y 
WHERE vid = '{$vid}' OR distance <= MaxOf5Dist 
ORDER BY distance