1

假设我有这些表:

[ 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)

我的访问者运行如下搜索:列出 5 月 1 日至 12 月 31 日期间每日价格(price_per_day 字段)在 10 到 100 之间的前 10 个(分页)属性

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

关于问题的问题

如果有差距,那会是可接受的属性吗?

没有空隙。所有可能的日期都在数据库中。

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

在完美的世界中,不......我们需要考虑所有变化/时期来计算该时期那种价格的“总和”。

另外,什么是“前10”?它们是如何排序的?先最低价?但价格可能不止一个。

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

4

3 回答 3

2

这类似于@mdma 给出的答案,但我在连接子句中使用了价格范围的条件,而不是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 |
+----+-------------+-------+-------+-----------------+-----------------+---------+-----------+------+--------------------------+
于 2010-05-12T22:43:57.013 回答
1

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

  • 房产的价格在那个时期可能会发生变化,每个子时期都会有一个 properties_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  

该查询不会为您提供价格或其他详细信息。那将需要进行额外的查询。但也许我的假设无论如何都是错误的。

于 2010-05-07T22:26:21.237 回答
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 上工作。)

于 2010-05-10T18:53:01.807 回答