2010-07-01 3 views
1

У меня есть два стола в ресторане, выполненный в php. Вся информация о типе ресторана, оборудовании, кухнях указана в таблице 2 «сток» со ссылкой на их идентификатор restuarant в таблице 1. Как я запускаю запрос, чтобы я мог получить весь ресторан, который обслуживает китайцев, а также обед и парковка?Высокофильтрованный поиск по нескольким условиям

Это не похоже на работу:

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

попробовать это ..

ВЫБРАТЬ r.name из ресторана как г РЕГИСТРИРУЙТЕСЬ стек, как S ON r.id = s.rest_id WHERE s.value = 'китайский' AND s.value = 'обед' и з .value = 'парковка';

1

Единственный способ, которым я знаю, делать что-то вроде этого, - это «поворот» данных - по существу, превращение строк в столбцы. Например. В настоящее время у вас есть 1 строка для каждого из ваших значений, но вы идеально хотите 1 строку для каждого ресторана, чтобы вы могли запросить значения.

Плохая новость заключается в том, что вам нужно знать все возможные значения в вашем заявлении select, или вам нужно будет использовать курсоры.

Ниже следует дать некоторое представление о том, как создать точку опоры:

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