0

現在、2 つの MySQL テーブルがあります

プロパティ

id    name 
1     Grove house
2     howard house
3     sunny side

高度なオプション

prop_id    name
1          Wifi
1          Enclosed garden
1          Swimming pool
2          Swimming pool

ご覧のとおり、表 2 にはプロパティに関する特定の機能が含まれています。

最大 3 つのオプションしかない場合、以下のクエリは問題なく機能しました。(少し遅いかもしれませんが、大丈夫です)今、物事はいくらか拡大し、検索できる最大12のオプションがあり、それがいくつかの主要な速度の問題を引き起こしています。以下のクエリは 8 つのオプションに対するもので、ご覧のとおり非常に面倒です。私が達成しようとしていることを行うためのより良い方法はありますか?

SELECT * FROM properties WHERE id in (
select prop_id from advanced_options where name = 'Within 2 miles of sea or river' and prop_id in ( 
    select prop_id from advanced_options where name = 'WiFi' and prop_id in ( 
        select prop_id from advanced_options where name = 'Walking distance to pub' and prop_id in ( 
            select prop_id from advanced_options where name = 'Swimming pool' and prop_id in ( 
                select prop_id from advanced_options where name = 'Sea or River views' and prop_id in ( 
                    select prop_id from advanced_options where name = 'Pet friendly' and prop_id in ( 
                        select prop_id from advanced_options where name = 'Open fire, wood burning stove or a real flame fire-place' and prop_id in ( 
                            select prop_id from advanced_options where name='Off road parking') 
                        ) 
                    ) 
                ) 
            ) 
        ) 
    ) 
)
4

4 に答える 4

3

Mike Brant が提案するように、データモデルを制限に変更して、propertiesテーブルにこれらのそれぞれの列を作成することを検討します。しかし、上司が来ることがあります:「「フラットスクリーンテレビ」も必要です」と、DBに戻ってスキームとデータアクセスレイヤーを更新する必要があります。

データベースがビットごとの比較を使用する場合、このロジックを何らかの形で移動する方法。これにより、単純なクエリを作成できますが、クエリを作成する前に少し前処理が必要です。

自分で判断してください。

私はあなたのためにすべてをテストスイートに入れました ここにsqlfiddle

基本的な考え方は、テーブル内の各プロパティには 2 の累乗である ID があるということです。次のように:

INSERT INTO `advanced_options` (id, name)
VALUES
 (1, 'Wifi'),
 (2, 'Enclosing Garden'),
 (8, 'Swimming Pool'),
 (16, 'Grill');

次に、プロパティ テーブルに単一の値を格納し、オプションを追加して購入できます。

Wifi + Swimming Pool = 1 + 8 = 9

Wi-Fi とスイミング プールを備えたすべてのプロパティを検索する場合は、次のようにします。

SELECT * FROM `properties` WHERE `advanced_options` & 9 = 9

スイミングプールだけが必要な場合は、次のようになります。

SELECT * FROM `properties` WHERE `advanced_options` & 8 = 8

フィドルを試してみてください

于 2012-09-12T17:55:00.483 に答える
0

テーブルのスキーマ変更を検討する必要があります。高度なオプション自体にはプロパティがないように思われるため、advanced_options多対多の JOIN テーブルになろうとしているテーブルの代わりに、property_options各「オプション」のフィールドを持つテーブルを用意してみませんか。このようなもの

|prop_id  | wifi |  swimming_pool  |  etc..
-----------------------------------
|   1     |  0   |        1        |
|   2     |  1   |        0        |

ここで、各フィールドは、0/1 ブール表現を持つ単純な TINYINT フィールドです。

次のようにクエリできる場所に:

SELECT * FROM properties AS p
INNER JOIN property_options AS po ON p.id = po.prop.id
WHERE wifi = 1 AND swimming_pool = 1 ....

WHEREここでは、クエリ対象のオプションに基づいて句を作成するだけです。

これらのレコードはプロパティと 1 対 1 の関係を持つため、別のテーブルを用意する必要さえありません。必要に応じて、これらのフィールドをプロパティ テーブルに正規化できます。

于 2012-09-12T16:54:31.713 に答える
0

advanced_options テーブルに複数回参加します。2(泡立てる、すすぐ、繰り返す)のサンプルです。

select o1.prop_id
from advanced_options o1
inner join advanced_options o2 on o1.prop_id = o2.prop_id and o2.name = "WiFi"
where o1.name = 'Within 2 miles of sea or river'
于 2012-09-12T17:23:52.687 に答える
0

次のようなことができますか?:

select p.*,count(a.prop_id) as cnt
from properties p
inner join advanced_options a on a.prop_id = p.id
where a.name in ('Enclosed garden','Swimming pool')
group by p.name
having cnt = 2

そのクエリは、これらのすべてのadvanced_optionsを持つすべてのプロパティを取得します...

また、一意の Option 値を格納する別のテーブル Called を作成してテーブルを正規化し、そのAdvanced_option (id,name)ようなジャンクション エンティティ テーブルを作成して、Property_x_AdvancedOption (fk_PropertyID, FK_AdvancedOptionID)使用するリソースを減らし、データの整合性の問題を回避することもお勧めします。

于 2012-09-12T17:27:25.757 に答える