0

目前我有两个 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

如您所见,表二包含有关属性的特定功能

当我只有最多 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表中的每一个设置和创建一个列。但有时老板来了:“我们还需要'平板电视'”,然后你必须回到数据库并更新方案和数据访问层。

如果数据库使用按位比较,则可以以某种方式将此逻辑移出。这使您可以进行简单的查询,但在进行查询之前需要进行一些预处理。

自己判断。

我在这里为你把所有东西都放在了一个测试套件中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

如果你想找到所有有 wifi 和游泳池的房产,你可以这样做:

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        |

这里每个字段都是一个简单的 TINYINT 字段,具有 0/1 布尔表示。

到你可以查询的地方:

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根据要查询的选项构建您的子句。

实际上甚至不需要单独的表,因为这些记录将与属性具有一对一的关系,因此您可以根据需要将这些字段规范化到您的属性表中。

于 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_option (id,name),您可以在其中存储唯一的选项值,然后创建一个连接实体表Property_x_AdvancedOption (fk_PropertyID, FK_AdvancedOptionID),这样您可以使用更少的资源并避免数据完整性问题。

于 2012-09-12T17:27:25.757 回答