具有两个表以及多个数据和价格范围的复杂查询

时间:2010-05-07 20:00:56

标签: mysql date-range

我们假设我有这些表:

[ properties ]
 id (INT, PK)
 name (VARCHAR)

[ properties_prices ]
 id (INT, PK)
 property_id (INT, FK)
 date_begin (DATE)
 date_end (DATE)
 price_per_day (DECIMAL)
 price_per_week (DECIMAL)
 price_per_month (DECIMAL)

我的访问者会搜索以下内容:列出前一天的10个(分页)属性,其中每天的价格(price_per_day字段)在1月5日到12月31日期间的10到100之间 < / p>

我知道这是一个巨大的查询,我需要对结果进行分页,所以我必须完成所有计算并只在一个查询中登录...这就是我在这里的原因! :)

有关问题的问题

如果存在差距,那是否属于可接受的财产?

没有差距。所有可能的日期都在数据库中。

如果某些支持期间的价格在10到100之间,但在其他期间不是,您想获得该房产吗?

在完美世界中,没有......考虑到所有变化/期间,我们需要计算该时期内该类型价格的“总和”。

另外,“前10名”是什么?他们是如何订购的?价格最低?但可能有不止一个价格。

这只是每页10个结果的分页示例...可以通过FULLTEXT搜索订购,我将添加关键字和这些东西......正如我所说,这是一个非常大的查询。

3 个答案:

答案 0 :(得分:2)

这类似于@mdma给出的答案,但我在join子句中使用了一个条件来代替价格范围,而不是HAVING技巧。

SELECT p.id, MAX(p.name), 
  MIN(v.price_per_day) AS price_low,
  MAX(v.price_per_day) AS price_high
FROM properties p
JOIN properties_prices v ON p.id = v.property_id
  AND v.price_per_day BETWEEN 10 AND 100  
  AND v.date_begin < '2010-12-31' AND v.date_end > '2010-05-01'
GROUP BY p.id
ORDER BY ...
LIMIT 10;

我还建议创建覆盖索引:

CREATE INDEX prices_covering ON properties_prices
  (property_id, price_per_day, date_begin, date_end);

这允许您的查询以尽可能最佳的方式运行,因为它可以直接从索引中读取值。它根本不必从表中读取数据行。

+----+-------------+-------+-------+-----------------+-----------------+---------+-----------+------+--------------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref       | rows | Extra                    |
+----+-------------+-------+-------+-----------------+-----------------+---------+-----------+------+--------------------------+
|  1 | SIMPLE      | p     | index | PRIMARY         | PRIMARY         | 4       | NULL      |    1 |                          |
|  1 | SIMPLE      | v     | ref   | prices_covering | prices_covering | 4       | test.p.id |    6 | Using where; Using index |
+----+-------------+-------+-------+-----------------+-----------------+---------+-----------+------+--------------------------+

答案 1 :(得分:1)

你告诉我们的不够精确。从您的数据结构和您的问题我假设:

  • 在此期间,物业的价格可能会发生变化,并且每个子期间都会有一个property_price条目
  • 子期间不应有重叠,但数据结构不保证
  • 子期间可能存在空白

但仍有疑问:

  • 如果有差距,这是否属于可以接受的财产?
  • 如果某些支持期间的价格在10到100之间,但在其他期间没有,你想获得该房产吗?
  • 另外,“前10名”是什么?他们是如何订购的?价格最低?但可能有不止一个价格。

根据答案的不同,可能没有单一的查询可以解决问题。但是,如果你接受这些差距,那可能会得到你想要的东西:

SELECT *
FROM properties AS p
WHERE EXISTS          -- property is available in the price range
     (SELECT * FROM properties_prices AS pp1 
      WHERE p.id = pp1.property_id AND
            pp1.price_per_day between 10 and 100 AND
            (pp1.date_begin <= "2010-12-31" OR pp1.date_end >= "2010-05-01")) AND
      NOT EXISTS      -- property is in the price range in all sup-periods, but there might be gaps
     (SELECT * FROM properties_prices AS pp2 
      WHERE p.id = pp2.property_id AND
            pp2.price_per_day not between 10 and 100 AND
            (pp2.date_begin <= "2010-12-31" OR pp2.date_end >= "2010-05-01"))
ORDER BY name  --- ???
LIMIT 10  

该查询未向您提供价格或其他详细信息。这需要进行额外的查询。但也许我的假设都是错的。

答案 2 :(得分:1)

这也可以作为GROUP BY来完成,我认为这将是非常有效的,并且我们将一些聚合作为包的一部分:

SELECT 
   prperty_id, MIN(price_per_day), MAX(price_per_day)
FROM 
   properties_prices 
WHERE 
   date_begin <= "2010-12-31" AND date_end >= "2010-05-01"
GROUP BY 
   property_id
HAVING MIN(IF( (price_per_day BETWEEN 10 AND 100), 1, 0))=1
ORDER BY ...
LIMIT 10

(我没有手持MySQL,所以我没有测试过。我不确定MIN(IF ...)但使用CASE的模型在SQLServer上工作。)