2011-02-17 29 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