MySQL子查询重用

时间:2011-02-17 06:30:15

标签: php sql mysql

嘿伙计们。我有一个相当笨拙的SQL查询:

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,所以我不认为常见的表表达式是一种选择。另外,我遇​​到了临时表的麻烦。有没有办法用这种方式来表达这个查询,我可以重用距离计算?

另外,我知道我计算距离的方式与给定的geolat,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>=@max, @c+1, @c),
        @max := if(fp = 0
                   AND dp IS NULL
                   AND @d>=@max
                   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

谢谢理查德!

2 个答案:

答案 0 :(得分:2)

伪代码 - 如果需要,我会稍后修复代码,但这可能会让你开始自己找到答案。 MySQL允许你做疯狂的事情!

SELECT
    username,
    distance
FROM
(
SELECT
    username,
    @d:=distance AS distance,
    @c   := if(fp = 0
               AND dp IS NULL
               AND @d>=@max, @c+1, @c),
    @max := if(fp = 0
               AND dp IS NULL
               AND @d>=@max
               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

答案 1 :(得分:0)