【问题标题】:GROUP_CONCAT and LEFT_JOIN - filter recordsGROUP_CONCAT 和 LEFT_JOIN - 过滤记录
【发布时间】:2017-04-25 07:51:14
【问题描述】:

以下查询显示汤列表,以及每种汤的成分列表。

     //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;
 }
  ...

【问题讨论】:

    标签: mysql sql join concat


    【解决方案1】:

    也许只是一个有条件的从句?

    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 
    

    如果您想查找同时包含土豆和奶酪的食谱,您可以在 in 子句中添加奶酪并将值更改为 =2

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

    这假设每种成分只会在每个食谱中列出一次。

    由于您知道要寻找的成分,因此您可以动态调整拥有中的相等计数。

    【讨论】:

    • 我一直在我的帖子的简单示例中测试您的解决方案,它也很有效。我用多个条件案例编辑了我的帖子。如果您有任何其他建议,请提前致谢。
    • 如果上面的'potatoes'1 成为绑定参数,我看不到问题'potatoes' 可能是'potatoes','chicken','pork' 而第二个参数是3(计数数组中的 3 项)
    • 感谢 xQbert。我编辑我的帖子。我喜欢您的解决方案,但我仍然无法使其适用于我的情况。我也尝试将这部分查询放在 GROUP BY 之后,但也没有用。我正在做几项测试,试图弄清楚发生了什么。
    【解决方案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
    

    【讨论】:

    • 我一直在我的帖子的简单示例中测试您的解决方案,效果很好。但是我无法应用于我的真实案例,因为它正在过滤多个条件。我编辑了我的帖子。如果您有更多建议,请提前致谢。
    猜你喜欢
    • 2013-07-05
    • 2010-12-11
    • 2010-09-22
    • 2018-04-26
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    相关资源
    最近更新 更多