2012-07-20 2 views
3

마지막 작품 중 하나는 Yii 기반 하드웨어 카탈로그입니다. 각 항목은 많은 그룹과 연결될 수 있습니다.MySQL에서 SQL INTERSECT를 구현하는 동안 중첩 수준이 너무 높습니다.

CREATE TABLE item_group (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
itemId INT(10) UNSIGNED NOT NULL, 
groupId INT(10) UNSIGNED NOT NULL, 
PRIMARY KEY (id) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

사용자가 선택한 모든 groupIds가있는 itemIds 만 표시하면됩니다. 여기에 내 버그 솔루션이 있습니다 :

$groups = isset($_GET['groups']) ? array_merge(array_diff($_GET['groups'], array('0'=>'-')),array()) : array(); 
$sql = ''; 
$brackets = ''; 
$groupMaxKey = count($groups) - 1; 
//some code here 
for($i=0;$i<=$groupMaxKey;$i++){ 
    $sql .= "SELECT itemId FROM item_group WHERE groupId='".$groups[$i]."' "; 
    if($i != $groupMaxKey){ 
     $sql .= "AND itemId IN ("; 
     $brackets .= ")"; 
    } else { 
     $sql .= $brackets; 
    } 
} 

중첩의 최대 레벨이 32임을 알게되었습니다. 더 많은 그룹이 오류를 발생시킵니다. 무엇이 가장 깨끗한 해결책이 될까요?

SELECT itemId FROM item_group 
WHERE groupId='31' AND itemId IN (
    SELECT itemId FROM item_group 
    WHERE groupId='24' AND itemId IN (
     SELECT itemId FROM item_group 
     WHERE groupId='35' 
    ) 
) 

//// 대답 정말로 작동 :

SELECT g1.itemId 
FROM (((((((((((((((((((((((((((((((((((((((item_group g1 
INNER JOIN item_group g2 ON g1.itemId = g2.itemId) 
INNER JOIN item_group g3 ON g1.itemId = g3.itemId) 
INNER JOIN item_group g4 ON g1.itemId = g4.itemId) 
INNER JOIN item_group g5 ON g1.itemId = g5.itemId) 
INNER JOIN item_group g6 ON g1.itemId = g6.itemId) 
INNER JOIN item_group g7 ON g1.itemId = g7.itemId) 
INNER JOIN item_group g8 ON g1.itemId = g8.itemId) 
INNER JOIN item_group g9 ON g1.itemId = g9.itemId) 
INNER JOIN item_group g10 ON g1.itemId = g10.itemId) 
INNER JOIN item_group g11 ON g1.itemId = g11.itemId) 
INNER JOIN item_group g12 ON g1.itemId = g12.itemId) 
INNER JOIN item_group g13 ON g1.itemId = g13.itemId) 
INNER JOIN item_group g14 ON g1.itemId = g14.itemId) 
INNER JOIN item_group g15 ON g1.itemId = g15.itemId) 
INNER JOIN item_group g16 ON g1.itemId = g16.itemId) 
INNER JOIN item_group g17 ON g1.itemId = g17.itemId) 
INNER JOIN item_group g18 ON g1.itemId = g18.itemId) 
INNER JOIN item_group g19 ON g1.itemId = g19.itemId) 
INNER JOIN item_group g20 ON g1.itemId = g20.itemId) 
INNER JOIN item_group g21 ON g1.itemId = g21.itemId) 
INNER JOIN item_group g22 ON g1.itemId = g22.itemId) 
INNER JOIN item_group g23 ON g1.itemId = g23.itemId) 
INNER JOIN item_group g24 ON g1.itemId = g24.itemId) 
INNER JOIN item_group g25 ON g1.itemId = g25.itemId) 
INNER JOIN item_group g26 ON g1.itemId = g26.itemId) 
INNER JOIN item_group g27 ON g1.itemId = g27.itemId) 
INNER JOIN item_group g28 ON g1.itemId = g28.itemId) 
INNER JOIN item_group g29 ON g1.itemId = g29.itemId) 
INNER JOIN item_group g30 ON g1.itemId = g30.itemId) 
INNER JOIN item_group g31 ON g1.itemId = g31.itemId) 
INNER JOIN item_group g32 ON g1.itemId = g32.itemId) 
INNER JOIN item_group g33 ON g1.itemId = g33.itemId) 
INNER JOIN item_group g34 ON g1.itemId = g34.itemId) 
INNER JOIN item_group g35 ON g1.itemId = g35.itemId) 
INNER JOIN item_group g36 ON g1.itemId = g36.itemId) 
INNER JOIN item_group g37 ON g1.itemId = g37.itemId) 
INNER JOIN item_group g38 ON g1.itemId = g38.itemId) 
INNER JOIN item_group g39 ON g1.itemId = g39.itemId) 
INNER JOIN item_group g40 ON g1.itemId = g40.itemId) 
WHERE g1.groupId='1' AND g2.groupId='2' AND g3.groupId='3' AND g4.groupId='4' AND g5.groupId='5' AND g6.groupId='6' AND g7.groupId='7' AND g8.groupId='8' AND g9.groupId='9' AND g10.groupId='10' AND g11.groupId='11' AND g12.groupId='12' AND g13.groupId='13' AND g14.groupId='14' AND g15.groupId='15' AND g16.groupId='16' AND g17.groupId='17' AND g18.groupId='18' AND g19.groupId='19' AND g20.groupId='20' AND g21.groupId='21' AND g22.groupId='22' AND g23.groupId='23' AND g24.groupId='24' AND g25.groupId='25' AND g26.groupId='26' AND g27.groupId='27' AND g28.groupId='28' AND g29.groupId='29' AND g30.groupId='30' AND g31.groupId='31' AND g32.groupId='32' AND g33.groupId='33' AND g34.groupId='34' AND g35.groupId='35' AND g36.groupId='36' AND g37.groupId='37' AND g38.groupId='38' AND g39.groupId='39' AND g40.groupId='40' 
+0

당신은 어떻게 Drewch의 솔루션을 사용하지만 hackattack 년대 받아 와서? : P –

답변

4

INNER JOIN을 사용하여이를 수행 할 수 있습니다. 이 문장을 중첩 할 이유가 없습니다.

귀하의 예제 케이스에 대한 적절한 쿼리의 모든 예

는 다음과 같습니다 나는 세 개의 열 (id, itemId, groupId)있는 간단한 테이블에이 테스트를했는데 작동

SELECT g1.itemId 
FROM ((item_group g1 
     INNER JOIN item_group g2 ON g1.itemId = g2.itemId) 
     INNER JOIN item_group g3 ON g1.itemId = g3.itemId) 
WHERE g1.groupId='31' AND g2.groupId='24' AND g3.groupId='35' 

. 이런 종류의 구문을 루프에 넣는 것은 매우 쉽고 조인의 수에는 최대가 없습니다.

더 빠르게 실행하려면 item_group 테이블에 itemId 열의 색인을 생성해야합니다.

다음과 같은 SQL 문을 사용하여이 작업을 수행 할 수 있습니다

ALTER TABLE item_group ADD INDEX (itemId) 
+0

감사합니다. MySQL은이 솔루션을 찾는데별로 좋지 않았습니다. =) –

+0

인덱스를 추가하면 매우 빠르게 작업 할 수있어서 좋았습니다. groupId에 대한 색인도 추가하는 것이 좋습니다. – Drewch

+0

내 웹 사이트가 제품으로 가득차있을 때 두 솔루션의 속도에 대해 신속하게 답하겠습니다. 이것이 많은 사람들이 올바른 선택을하는 데 도움이된다고 생각하십시오. –

1

내가 바로이 문제를 이해한다면, 당신이를 찾기 위해 노력하고 나타납니다

여기에 쿼리의 예를 명확히하기 위해 다른 그룹의 itemIds 교차

우리가 할 수있는 것은 우리는 두 번 항목이 같은 그룹에있을 수없는만큼, 이제 ... 우리가보고있는 그룹에있는 모든 itemIds을 계산

SELECT itemId, COUNT(groupId) as CNT 
FROM item_group 
WHERE groupId IN (*GROUP_IDS*) 
GROUP BY itemId 

입니다 CNT는 수 우리가보고있는 그룹의 동일 whos는 그냥 ...이 쿼리에서

SELECT * FROM (
    SELECT itemId, COUNT(groupId) as CNT 
    FROM item_group 
    WHERE groupId IN (*GROUP_IDS*) 
    GROUP BY itemId 
) as TMP WHERE CNT = *NUMBER_OF_GROUP_IDS* 

를 행을 뽑을 수 그리고 그것을해야한다.

+0

당신의 대답도 작동하고 지금 관계를 생성하는 동안 중복 된 행을 방지하면 더 좋아 보인다. 내가 맞습니까? –

+0

성능, 내 솔루션 또는 내부 조인 성능이 확실하지 않습니다. 그것은 그 자체로 흥미로운 질문입니다. 필자가 생각하기에, SQL의 크기가 작을수록 이해하기 쉬워진다. 때로 가독성이 성능보다 중요합니다. – hackattack

관련 문제