2016-12-09 1 views
0

다음 쿼리는 스프 목록과 각 스프에 대한 목록을 표시합니다.GROUP_CONCAT 및 LEFT_JOIN - 필터 레코드

 //Query only for demonstration 

    SELECT a.id_soup, a.soup,  
    GROUP_CONCAT(DISTINCT b.id_vegetables) AS vegetables_id, 
    GROUP_CONCAT(DISTINCT b.vegetables) AS vegetables_list 
    FROM soups a 
    LEFT JOIN ingredients ing ON a.soup = ing.soup_id 
    LEFT JOIN vegetables b ON b.id_vegetables = ing.list_vegetables 
    GROUP BY a.id_soup 

수프에 특정 성분 (예 : 감자)이있는 레코드 만 필터링되도록 레코드를 필터링하고 싶습니다. 같은 뭔가 :

 SELECT a.id_soup, a.soup,  
    GROUP_CONCAT(DISTINCT b.id_vegetables) AS vegetables_id, 
    GROUP_CONCAT(DISTINCT b.vegetables) AS vegetables_list 
    FROM soups a 
    LEFT JOIN ingredients ing ON a.soup = ing.soup_id 
    LEFT JOIN vegetables b ON b.id_vegetables = ing.list_vegetables 

    AND ing.list_vegetables LIKE "potatoes" 

    GROUP BY a.id_soup 

이 쿼리는 레코드를 필터링 없지만, 성분의 목록은 더 이상 단지 성분 감자를 표시 수프의 모든 성분을 표시합니다.

이 작업을 올바르게 수행하는 가장 좋은 방법은 무엇입니까?

편집 :

에 여러 조건으로 - PHP와 SQL : 당신이 야채의 목록을 얻을 후

$typesQuery = ""; 
    $bind=array(); 

    sqlQuery = "SELECT a.id_soup, a.soup, a.restaurant,  
    GROUP_CONCAT(DISTINCT b.id_vegetables) AS vegetables_id, 
    GROUP_CONCAT(DISTINCT b.vegetables) AS vegetables_list 
    FROM soups a 
    LEFT JOIN ingredients ing ON a.soup = ing.soup_id 
    LEFT JOIN vegetables b ON b.id_vegetables = ing.list_vegetables "; 

if($restaurant) { 
    $sqlQuery .= " AND a.restaurant LIKE ? "; 
    $typesQuery .= "s" ; 
    $bind[] = $restaurant; 
} 


if($vegetables) { 
    $sqlQuery .= " AND ... "; 
    $typesQuery .= "s" ; 
    $bind[] = $vegetables; 
} 

//EDITED: 
$vegetables = 'potatoes'; 
if($vegetables) { 
    $sqlQuery .= " HAVING SUM(CASE WHEN b.vegetables IN (?) THEN 1 ELSE 0 END) = 1 "; 
    $typesQuery .= "s" ; 
    $bind[] = $vegetables; 
} 


$sqlQuery .= " GROUP BY a.id_soup LIMIT ?,? "; 

if ($statementQuery = $conexion->prepare($sqlQuery)){ 

    $typesTotal = $typesQuery; 
    $bindTotal = array_merge(array(), $bind); 

    $typesQuery .= "ii"; 
    $bind[] = $start; 
    $bind[] = $limit; 
    array_unshift($bind, $typesQuery); 
    call_user_func_array( array($statementQuery, 'bind_param'), makeValuesReferenced($bind)); 

}else{ 
    $error = $conexion->error; 
    $success = false; 
    break; 
} 
    ... 

답변

2

사용 FIND_IN_SET.

SELECT * FROM (
SELECT a.id_soup, 
GROUP_CONCAT(DISTINCT b.id_vegetables) AS vegetables_id, 
GROUP_CONCAT(DISTINCT b.vegetables) AS vegetables_list 
FROM soups a 
LEFT JOIN ingredients ing ON a.soup = ing.soup_id 
LEFT JOIN vegetables b ON b.id_vegetables = ing.list_vegetables 
GROUP BY a.id_soup 
) X 
WHERE FIND_IN_SET('POTATOES',VEGETABLES_LIST) > 0 
+0

내 게시물의 간단한 예제에서 솔루션을 테스트 해봤는데 잘 작동합니다. 그러나 여러 조건으로 필터링되기 때문에 실제 사례에는 적용 할 수 없습니다. 내 게시물을 편집했습니다. 더 많은 제안이 있으면 미리 감사드립니다. – josei

1

아마도 조건부 조항이 있습니까? 둘 다 감자를했다 치즈 당신이 절에 치즈를 추가 할 수 있습니다 만이 각각의 성분을 가정 = 2

HAVING sum(case when b.vegetables in ('potatoes','cheese') then 1 else 0 end) = 2

로 값을 것이다 변경 조리법을 발견하고 싶었다면

SELECT a.id_soup, a.soup,  
GROUP_CONCAT(DISTINCT b.id_vegetables) AS vegetables_id, 
GROUP_CONCAT(DISTINCT b.vegetables) AS vegetables_list 

FROM soups a 
LEFT JOIN ingredients ing ON a.soup = ing.soup_id 
LEFT JOIN vegetables b ON b.id_vegetables = ing.list_vegetables 
GROUP BY a.id_soup 
HAVING sum(case when b.vegetables in ('potatoes') then 1 else 0 end) = 1 

레시피 당 한 번씩 나열하십시오.

당신이 찾고있는 재료를 알고 있기 때문에 동적으로 동등한 수를 조절할 수 있습니다.

+0

나는 내 게시물의 간단한 예제에서 당신의 솔루션을 테스트 해왔고 너무 효과적입니다. 여러 조건이있는 게시물을 편집했습니다. 더 많은 제안이 있으면 미리 감사드립니다. – josei

+0

위의 "potatoes"와 "1"이 바인딩 된 매개 변수가되면 "potatoes"는 "potatoes", "chicken", "pork"일 수 있고 두 번째 매개 변수는 '3' (배열의 3 개 항목 수) – xQbert

+0

감사 xQbert. 내 게시물을 편집합니다. 나는 당신의 해결책이 마음에 들지만, 나는 아직도 나의 경우에 효과가있게 만들지 못했다. 또한 GROUP BY 후에 쿼리의이 부분을 넣으려고했으나 작동하지 않았습니다. 나는 무슨 일이 일어나고 있는지 알아 내려고 몇 가지 테스트를하고 있습니다. – josei