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 日までの期間で、1 日あたりの価格 (price_per_day フィールド) が 10 から 100 の間である最初の 10 (ページネーション) プロパティをリストします

私はそれが巨大なクエリであることを知っており、結果をページ分割する必要があるため、すべての計算を実行し、1 つのクエリでログインする必要があります...それが私がここにいる理由です! :)

問題に関する質問

ギャップがある場合、それは許容可能なプロパティでしょうか?

隙間はありません。可能な日付はすべてデータベースにあります。

価格が 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

これはGROUPBYとしても実行できますが、これは非常に効率的だと思います。パッケージの一部としていくつかの集計を取得します。

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 に答える
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 に答える