2010-07-01 77 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