0

我有一张邮政编码表:

id INT, postcode VARCHAR(8)

以及这些邮政编码之间的距离表,该表仅存储两个不同邮政编码之间的一个方向的距离,因此从邮政编码 ID 2 到邮政编码 ID 5,距离仅存储为2, 5, 78.2或存储为,5, 2, 78.2但不能同时存储。

from INT, to INT, dist DECIMAL

距离的主键是(从,到),我在该表的每一列上也有一个索引。

我有一个看起来像这样的查询:

SELECT *
FROM listings, postcode_distances,
     postcodes postcode_listings, postcodes postcode_searchterm
WHERE listing.`status` = 3
AND listings.category = 8
AND postcode_listings.id = listings.postcode_id
AND (
     (postcode_distances.to = postcode_listings.id AND
      postcode_distances.from = postcode_searchterm.id AND
      postcode_distances.dist < 30)
     OR
     (postcode_distances.from = postcode_listings.id AND
      postcode_distances.to = postcode_searchterm.id AND
      postcode_distances.dist < 30)
)
AND postcode_searchterm.postcode = 'AB11'
GROUP BY id_listings
ORDER BY postcode_distances.dist ASC;

查询运行缓慢(如您所料)并作为副作用锁定数据库。

解释查询显示 postcode_distances 连接的这一行:

1 | SIMPLE | postcode_distances | ALL | PRIMARY,dist,to,from | 695332 | Using where; Using join buffer

有什么方法可以在单个查询中实现两个连接(搜索的邮政编码是列from或列)?to

我可以使用 UNION 并只运行两次查询,但将 postcode_distance OR 条件的每一半放在每个查询中,但我想检查我是否错过了另一种更简单的方法?

4

4 回答 4

1
SELECT postcodes.id       AS SearchedId, 
       postcodes.postcode AS SearchedPostCode, 
       p1.postcode        AS FromPostCode, 
       p2.postcode        AS ToPostCode, 
       p1.id              AS FromPostCodeId, 
       p2.id              AS ToPostCodeId, 
       postcode_distances.dist 
FROM   listings 
       INNER JOIN postcodes 
         ON postcodes.id = listings.postcode_id 
       INNER JOIN postcode_distances 
         ON ( postcode_distances.to1 = postcodes.id 
               OR postcode_distances.from1 = postcodes.id ) 
       INNER JOIN postcodes p1 
         ON postcode_distances.From1 = p1.id 
       INNER JOIN postcodes p2 
         ON postcode_distances.to1 = p2.id 
WHERE  listings.status = 3 
       AND listings.category = 8 
       AND postcode_distances.dist < 30 
       AND postcodes.postcode = 'AB11' 
ORDER  BY postcode_distances.dist ASC; 

请参阅 Sql Fiddle 示例

于 2012-05-23T10:41:45.503 回答
0
SELECT   *
FROM     listings
  JOIN   postcodes postcode_listings ON postcode_listings.id = listings.postcode_id
  JOIN   postcodes postcode_searchterm
  JOIN   postcode_distances
    ON ( (listings.postcode_id, postcode_searchterm.id)
         IN (
           (postcode_distances.to,   postcode_distances.from),
           (postcode_distances.from, postcode_distances.to)
         )
     AND postcode_distances.dist < 30
    )
WHERE    listings.status = 3
     AND listings.category = 8
     AND postcode_searchterm.postcode = 'AB11'
GROUP BY id_listings
ORDER BY postcode_distances.dist ASC;
于 2012-05-23T12:02:53.373 回答
0

这是一种不同的方法:

SELECT
  MAX(CASE p.id WHEN d.`from` THEN p.postcode END) AS from_postcode,
  MAX(CASE p.id WHEN d.`to`   THEN p.postcode END) AS to_postcode,
  d.`from`,
  d.`to`,
  d.`dist`,
  MAX(l.id_listings) AS id_listings
FROM postcode_distances d
INNER JOIN postcodes p ON p.id IN (d.`from`, d.`to`)
LEFT JOIN listings l ON l.postcode_id = p.id AND l.`status` = 3 AND l.category = 8
WHERE p.postcode =  'AB11' AND l.id_listings IS     NULL
   OR p.postcode <> 'AB11' AND l.id_listings IS NOT NULL
GROUP BY
  d.`from`,
  d.`to`,
  d.`dist`
HAVING COUNT(*) = 2

该查询使用到特定子集的外连接,listings并检索在该子集中具有匹配项或具有特定postcode. 然后对这些行进行分组,并确保这些组恰好有两行。

于 2012-05-23T14:08:11.580 回答
0

如果您发现有问题,请尝试此评论

 select * from listings, postcode_distances pDis,postcodes post
 WHERE listing.status = 3 AND listings.category = 8
 AND (pDis.to = post.id OR pDis.from = post.id) AND post.postcode = 'AB11' 
 AND pDis.dist < 30;
于 2012-05-23T11:59:45.607 回答