2010-07-01 37 views
1

我在php中完成了餐馆搜索中的两个表。关于餐厅类型,设施和美食的所有信息都参考表1中的餐厅ID,我们如何运行一个查询,以便我可以获得所有的餐厅,服务于中餐,还有供应晚餐并且也有停车位?基于多个条件的高度过滤搜索

这并不似乎工作:

SELECT DISTINCT restaurant.name, restaurant.place 
FROM stack,restaurant 
WHERE restaurant.id=stack.rest_id AND stack.value='chineese' 
     AND stack.value='dinner' AND stack.value='parking' 

这里是我的表结构

Table1 - **restaurant** 
------+----------+---------- 
    id + name + place 
------+----------+---------- 
    1  rest1  ny 
    2  rest2  la 
    3  rest3  ph 
    4  rest4  mlp 




Table2 - **stack** 
------+----------+------------------------- 
    id + rest_id +  type  + value 
------+----------+------------------------- 
    1  1   cuisine  chinese 
    2  1   serves  breakfast 
    3  1   facilities party hall 
    4  1   serves  lunch 
    5  1   serves  dinner 
    6  1   cuisine  seafood 
    7  2   cuisine  Italian 
    8  2   serves  breakfast 
    9  2   facilities parking 
    10  2   serves  lunch 
    11  2   serves  dinner 
    12  2   cuisine  indian 

也告诉我,如果这是错误的方法。我使用堆栈,因为美食,设施都可以是无限的,因为它没有定义,每个都非常适合。

回答

1

鉴于现有的结构,那是很容易的:

SELECT name, place FROM restaurant WHERE id IN (
    SELECT rest_id FROM stack 
    WHERE value IN ('chinese', 'dinner', 'parking') 
    GROUP BY rest_id 
HAVING COUNT(rest_id)=3); 

只要确保给HAVING COUNT(rest_id)的数值,您正在搜索值的数量相匹配。这里有一个简单的测试用例(即我已经加入另一家餐厅,其中居然有“中国”,“晚餐”和“停车”注:

CREATE TABLE `restaurant` (
    `id` int(11) NOT NULL auto_increment, 
    `name` VARCHAR(255), 
    `place` VARCHAR(255), 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

CREATE TABLE `stack` (
    `id` int(11) NOT NULL auto_increment, 
    `rest_id` int(11) NOT NULL, 
    `type` VARCHAR(255), 
    `value` VARCHAR(255), 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

INSERT INTO `restaurant` VALUES 
    (1, 'rest1', 'ny'), 
    (2, 'rest2', 'la'), 
    (3, 'rest3', 'ph'), 
    (4, 'rest4', 'mlp'); 

INSERT INTO `stack` VALUES 
    (1, 1, 'cuisine', 'chinese'), 
    (2, 1, 'serves',  'breakfast'), 
    (3, 1, 'facilities', 'party hall'), 
    (4, 1, 'serves',  'lunch'), 
    (5, 1, 'serves',  'dinner'), 
    (6, 1, 'cuisine', 'seafood'), 
    (7, 2, 'cuisine', 'Italian'), 
    (8, 2, 'serves',  'breakfast'), 
    (9, 2, 'facilities', 'parking'), 
    (10, 2, 'serves',  'lunch'), 
    (11, 2, 'serves',  'dinner'), 
    (12, 2, 'cuisine', 'indian'), 
    (13, 3, 'cuisine', 'chinese'), 
    (14, 3, 'serves',  'breakfast'), 
    (15, 3, 'facilities', 'parking'), 
    (16, 3, 'serves',  'lunch'), 
    (17, 3, 'serves',  'dinner'), 
    (18, 3, 'cuisine', 'indian'); 

SELECT name, place FROM restaurant WHERE id IN (
    SELECT rest_id FROM stack 
    WHERE value IN ('chinese', 'dinner', 'parking') 
    GROUP BY rest_id 
HAVING COUNT(rest_id)=3); 

+-------+-------+ 
| name | place | 
+-------+-------+ 
| rest3 | ph | 
+-------+-------+ 

SELECT name, place FROM restaurant WHERE id IN (
    SELECT rest_id FROM stack 
    WHERE value IN ('chinese', 'dinner') 
    GROUP BY rest_id 
HAVING COUNT(rest_id)=2); 

+-------+-------+ 
| name | place | 
+-------+-------+ 
| rest1 | ny | 
| rest3 | ph | 
+-------+-------+ 

SELECT name, place FROM restaurant WHERE id IN (
    SELECT rest_id FROM stack 
    WHERE value IN ('parking', 'hellipad') 
    GROUP BY rest_id 
HAVING COUNT(rest_id)=2); 

Empty set (0.00 sec) 

或者,您可以创建相关的表,这样的(但这是可能不是最好的结构):

          ---> facility 
restaurant ---> restaurant_has_facility ---| 
              ---> facility_type 

查询几乎是一样的,你只需要你的子查询产生适当的加入:

SELECT restaurant_name, restaurant_place FROM (
    SELECT 
     r.id AS restaurant_id, 
     r.name AS restaurant_name, 
     r.place AS restaurant_place, 
     ft.name AS facility_name 
    FROM restaurant AS r 
    JOIN restaurant_has_facility AS rf ON rf.restaurant_id = r.id 
    JOIN facility_type AS ft ON ft.id = rf.facility_type_id 
    ORDER BY r.id, ft.name) AS tmp 
WHERE facility_name IN ('chinese', 'dinner', 'parking') 
GROUP BY tmp.restaurant_id 
HAVING COUNT(tmp.restaurant_id)=3; 

下面是一些示例SQL对于上述结构:

CREATE TABLE `restaurant` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `name` VARCHAR(45) NOT NULL , 
    `place` VARCHAR(45) NOT NULL , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 

CREATE TABLE `facility` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `name` VARCHAR(45) NOT NULL , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 

CREATE TABLE IF NOT EXISTS `facility_type` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `name` VARCHAR(45) NOT NULL , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 

CREATE TABLE IF NOT EXISTS `restaurant_has_facility` (
    `restaurant_id` INT UNSIGNED NOT NULL , 
    `facility_id` INT UNSIGNED NOT NULL , 
    `facility_type_id` INT UNSIGNED NOT NULL , 
    PRIMARY KEY (`restaurant_id`, `facility_id`, `facility_type_id`) , 
    INDEX `fk_restaurant_has_facility_restaurant` (`restaurant_id` ASC) , 
    CONSTRAINT `fk_restaurant_has_facility_restaurant` 
    FOREIGN KEY (`restaurant_id`) 
    REFERENCES `restaurant` (`id`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE) 
ENGINE = InnoDB; 

INSERT INTO `restaurant` VALUES 
    (1, 'rest1', 'ny'), 
    (2, 'rest2', 'la'), 
    (3, 'rest3', 'ph'), 
    (4, 'rest4', 'mlp'); 

INSERT INTO `facility` VALUES 
    (1, 'cuisine'), 
    (2, 'serves'), 
    (3, 'facilities'); 

INSERT INTO `facility_type` VALUES 
    (1, 'chinese'), 
    (2, 'breakfast'), 
    (3, 'party hall'), 
    (4, 'lunch'), 
    (5, 'dinner'), 
    (6, 'seafood'), 
    (7, 'Italian'), 
    (8, 'parking'), 
    (9, 'indian'); 

INSERT INTO `restaurant_has_facility` VALUES 
    (1, 1, 1), 
    (1, 2, 2), 
    (1, 3, 3), 
    (1, 2, 4), 
    (1, 2, 5), 
    (1, 1, 6), 
    (2, 1, 7), 
    (2, 2, 2), 
    (2, 3, 8), 
    (2, 2, 4), 
    (2, 2, 5), 
    (2, 1, 9), 
    (3, 1, 1), 
    (3, 2, 5), 
    (3, 3, 8), 
    (3, 2, 4), 
    (3, 2, 2), 
    (3, 1, 9); 
0

试试这个..

SELECT r.name FROM餐厅为r JOIN堆栈S于r.id = s.rest_id WHERE s.value = '中国' AND s.value = '晚餐' 和S .value的= '停车';

1

我知道做这种事情的唯一方法是“旋转”数据 - 实质上是将行变为列。例如。您目前每个值都有1行,但理想情况下,每个餐厅都需要1行,以便查询值。

坏消息是,您需要知道选择语句中的所有可能值,否则您将需要使用游标。

下应该给一些想法如何创建枢轴:

SELECT   
    rest_id, 
    MAX(CASE WHEN s.value = 'chinese' THEN 1 ELSE 0 END) AS chinese, 
    MAX(CASE WHEN s.value = 'breakfast' THEN 1 ELSE 0 END) AS breakfast, 
    MAX(CASE WHEN s.value = 'party hall' THEN 1 ELSE 0 END) AS [party hall], 
    MAX(CASE WHEN s.value = 'lunch' THEN 1 ELSE 0 END) AS lunch, 
    MAX(CASE WHEN s.value = 'dinner' THEN 1 ELSE 0 END) AS dinner, 
    MAX(CASE WHEN s.value = 'seafood' THEN 1 ELSE 0 END) AS seafood, 
    MAX(CASE WHEN s.value = 'Italian' THEN 1 ELSE 0 END) AS Italian, 
    MAX(CASE WHEN s.value = 'parking' THEN 1 ELSE 0 END) AS parking, 
    MAX(CASE WHEN s.value = 'Indian' THEN 1 ELSE 0 END) AS indian 
FROM    
    stack AS s 
GROUP BY 
    rest_id 

这将创建一个表,看起来像:

rest_id | chinese | breakfast | party hall | lunch | dinner | seafood | Italian | parking | indian 
--------+---------+-----------+------------+-------+--------+---------+---------+---------+------- 
    1 | 1  |  1  |  1  | 1 | 1 | 1 | 0 | 0 | 0 
    2 | 0  |  1  |  0  | 1 | 1 | 0 | 1 | 1 | 1 

从该表是那么一个非常简单的加入让有特殊功能的餐厅。

例如:

SELECT restaurant.name, restaurant.place FROM restaurant LEFT JOIN 
    (SELECT   
    rest_id, 
    MAX(CASE WHEN s.value = 'chinese' THEN 1 ELSE 0 END) AS chinese, 
    MAX(CASE WHEN s.value = 'breakfast' THEN 1 ELSE 0 END) AS breakfast, 
    MAX(CASE WHEN s.value = 'party hall' THEN 1 ELSE 0 END) AS [party hall], 
    MAX(CASE WHEN s.value = 'lunch' THEN 1 ELSE 0 END) AS lunch, 
    MAX(CASE WHEN s.value = 'dinner' THEN 1 ELSE 0 END) AS dinner, 
    MAX(CASE WHEN s.value = 'seafood' THEN 1 ELSE 0 END) AS seafood, 
    MAX(CASE WHEN s.value = 'Italian' THEN 1 ELSE 0 END) AS Italian, 
    MAX(CASE WHEN s.value = 'parking' THEN 1 ELSE 0 END) AS parking, 
    MAX(CASE WHEN s.value = 'Indian' THEN 1 ELSE 0 END) AS indian 
    FROM    
    stack AS s 
    GROUP BY 
    rest_id) AS features 
ON 
    restaurant.id=features.rest_id 
WHERE 
    features.chinese=1 and features.dinner=1 and features.parking=1