2012-02-10 55 views
7

用户可以通过邮政编码(例如:L14,L15,L16)或文本框中的位置进行搜索。改进SQL查询以避免结合的另一种方法?

如果用户输入“利物浦”,它会找到所有位于“利物浦”的商店。如果用户输入邮政编码(例如:L15),它将搜索所有在L15邮政编码区域发货的商店。

请参见下表:

mysql> select * from shops; 
+----+----------+-----------+----------+ 
| id | name  | location | postcode | 
+----+----------+-----------+----------+ 
| 1 | Shop One | Liverpool | L10  | 
| 2 | Shop Two | Liverpool | L16  | 
+----+----------+-----------+----------+ 

-

mysql> select * from shops_delivery_area; 
+------------------+---------+----------+---------------+ 
| delivery_area_id | shop_id | postcode | delivery_cost | 
+------------------+---------+----------+---------------+ 
|    1 |  1 | L10  |   1.50 | 
|    2 |  1 | L11  |   0.00 | 
|    3 |  1 | L12  |   1.00 | 
|    4 |  1 | L13  |   1.00 | 
|    5 |  2 | L10  |   2.50 | 
|    6 |  2 | L16  |   0.00 | 
|    7 |  2 | L28  |   0.00 | 
+------------------+---------+----------+---------------+ 

SQL查询:

SELECT U.* FROM 
    ((SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on (DA.shop_id = shops.id) 
    WHERE DA.postcode = "Liverpool") 
    UNION 
    (SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on 
           (DA.shop_id = shops.id AND 
           DA.postcode = shops.postcode) 
    WHERE shops.location = "Liverpool")) as U 

-

结果 - 通过位置(利物浦):

+----+----------+-----------+----------+---------------+--------------+ 
| id | name  | location | postcode | delivery_cost | AreaPostcode | 
+----+----------+-----------+----------+---------------+--------------+ 
| 1 | Shop One | Liverpool | L10  |   1.50 | L10   | 
| 2 | Shop Two | Liverpool | L16  |   0.00 | L16   | 
+----+----------+-----------+----------+---------------+--------------+ 

结果 - 通过邮编(L12):

+----+----------+-----------+----------+---------------+--------------+ 
| id | name  | location | postcode | delivery_cost | AreaPostcode | 
+----+----------+-----------+----------+---------------+--------------+ 
| 1 | Shop One | Liverpool | L10  |   1.00 | L12   | 
+----+----------+-----------+----------+---------------+--------------+ 

它似乎正常工作... 是提高有其他的方式SQL查询更短,以避免union什么的?

+0

你对避免'UNION'什么道理呢?附:我认为你可以删除'DISTINCT'关键字,因为'UNION'是'UNION DISTINCT'的缩写。 – onedaywhen 2012-02-10 14:19:38

回答

1

无论你选择,要知道,短代码并不总是最优的代码。在很多情况下,如果你有足够的逻辑分歧,联合结果确实是最优的(有时候是最干净的,程序化的)选项。

这就是说,下面还是在WHERE子句中似乎涵盖你的情况......

SELECT DISTINCT 
    shops.*, 
    DA.delivery_cost, 
    DA.postcode AS AreaPostcode 
FROM 
    shops 
INNER JOIN 
    shops_delivery_area as DA 
    ON (DA.shop_id = shops.id) 
WHERE 
    (DA.postcode = "Liverpool") 
OR 
    (DA.postcode = shops.postcode AND shops.location = "Liverpool") 
+0

谢谢!那么在性能方面哪个更好?坚持使用联合或“或”在WHERE子句 – 2012-02-10 14:25:00

+0

我刚刚完成性能测试..它出现使用'联合'更快。 – 2012-02-10 14:59:18

+0

@ user791022 sayd'我刚刚完成了性能测试..它看起来使用联盟更快。**我告诉过你了**什么是更快的两个索引命中到表中或整个表的扫描?当您将“应用程序”思想(减少冗余代码等)应用于SQL时,会遇到性能问题。 – 2012-02-10 15:02:05

0

我错过了什么? 你为什么不能做

WHERE DA.postcode = "Liverpool" or shops.location = "Liverpool" 
+0

这将无法正常工作,否则您将获得多行相同的商店名称。仔细看看JOIN'。 – 2012-02-10 13:56:17

+1

使用“OR”可能会导致性能下降,具体取决于索引的使用方式。我通常会像这样将一个查询分解成一个'UNION'来避免'OR',并且在'UNION'的每个部分中使用一个索引会获得显着的性能提升。 – 2012-02-10 14:04:51

+0

@Diego,当它是'shops.location =“Liverpool”'时,你错过了一个限制。 – 2012-02-10 14:09:43

1

由于所有的表和选择的列都是一样的,你可以简单地这样做:

SELECT DISTINCT shops.*, DA.delivery_cost, DA.postcode AS AreaPostcode FROM shops 
      JOIN shops_delivery_area as DA on DA.shop_id = shops.id 
    WHERE (DA.postcode = "Liverpool") 
     OR (DA.postcode = shops.postcode AND shops.location = "Liverpool") 

就像你在迭戈的回答说,条件是痘痘的不同!所以,你补偿WHERE clause的差异。

0

请试试这个:

SELECT DISTINCT shops.*, 
     DA.delivery_cost, 
     DA.postcode 
FROM shops 
     JOIN shops_delivery_area as DA on DA.shop_id = shops.id 
WHERE DA.postcode = "Liverpool" 
     OR (location = "Liverpool" and DA.postcode = shops.postcode)