2010-07-01 3 views
1

나는 PHP에서 행해진 레스토랑 검색에서 두 개의 테이블을 가지고 있습니다. 레스토랑 유형, 시설, 요리에 대한 모든 정보는 Table2에 입력되어 있습니다 - 테이블 1의 restuarant ID를 참조하여 '스택'합니다. 어떻게 chineese를 제공하는 모든 레스토랑을 얻을 수 있도록 쿼리를 실행합니까? 저녁 식사를 제공하고 주차 할 수 있습니까?여러 조건을 기반으로 고도로 필터링 된 검색

이 작동하는 것 같다하지 않습니다

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)에 주어진 숫자 값은 당신이 검색하는 값의 수를 일치하는지 확인 . 다음은 간단한 테스트 케이스 (I 실제로 '중국어', '저녁 식사'와 '주차'가 또 다른 레스토랑, 추가 한 노트입니다 : 또는

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.id = s.rest_id WHERE s.value = '중국어'AND s.value = '저녁 식사'와 S를 ON이야로 스택을 가입 R로 레스토랑 FROM

SELECT r.name .value = '주차';

1

내가 이런 식으로 알고있는 유일한 방법은 데이터를 "피벗 (pivot)"하는 것입니다. 기본적으로 행을 열로 만듭니다. 예 : 현재 각 값에 대해 1 행이 있지만 값을 쿼리 할 수 ​​있도록 각 레스토랑마다 1 행이 필요합니다.

나쁜 소식은 select 문에서 가능한 모든 값을 알아야하거나 커서를 사용해야한다는 것입니다.

어떻게 '피벗 만드는 몇 가지 아이디어를 제공해야합니다 다음은 간단한을 얻기 위해 가입 꽤 그럼이 표에서

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   
    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 

이 보이는 테이블을 만들 것 특별한 기능을 가진 레스토랑. 예를 들어

:

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