SQL query to match a comma-separated string against a comma-separated string?

前端 未结 3 1739
长情又很酷
长情又很酷 2020-12-22 04:57

The MySQL query below uses PHP to pull in the $sector, which is a single digit, and the $subsector_text, which is a comma separated string. The $subsector_text could be a

相关标签:
3条回答
  • 2020-12-22 05:33

    The solution was to refactor the app. It took a couple days, but the offending code is gone and a new subsector table was created. Thanks everyone.

    0 讨论(0)
  • 2020-12-22 05:35

    It's not practical to match any value in a comma-separate string against any value in another comma-separated string in a single predicate.

    You can use FIND_IN_SET() to search for one value at a time.

    This means you need multiple predicates, one for each value you get by splitting your input $subsector_text. So split your variable and map it into a series of FIND_IN_SET() calls.

    I haven't tested the following code, but it should give you the idea of what I'm talking about:

    $subsector_array = array_map('intval', explode(',', $subsector_text));
    $subsector_terms = array_map(
      function ($id) { return "FIND_IN_SET($id, a.subsector)"; },
      $subsector_array);
    $subsector_expr = implode(' OR ', $subsector_terms);
    
    $sql = "
    SELECT ...
              WHERE a.state = 1 
                AND a.sector = '$sector'
                AND ($subsector_expr)
    ...";
    

    This will of course force a table-scan because there's no way to index FIND_IN_SET(), or any other operation that searches for substrings. Well, I suppose your conditions on a.state and a.sector will use an index to narrow down the search before applying the FIND_IN_SET() conditions.

    I understand the dilemma of having to work with a system that you inherited. Let your manager know that this needs to get refactored at some point, because it will never be efficient or reliable the way it's designed now.

    0 讨论(0)
  • 2020-12-22 05:56

    Your approach is correct, but need some modifications. Instead of try to match in only one condition (REGEXP), can create multiple conditions joined with OR...

    Example:

    $subsectorArray = explode(',', $subsector_text);
    $or = [];
    foreach ($subsectorArray as $subsector){
        $or[] = "a.subsector REGEXP '[^[:alnum:]]{$subsector}[^[:alnum:]]|^{$subsector}[^[:alnum:]]|[^[:alnum:]]{$subsector}$|^{$subsector}$'";
    }
    $orStr = implode(' OR ', $or);
    
     $sql = "
    SELECT DISTINCT a.id
                  , a.name
                  , a.category_id
                  , a.sector
                  , a.subsector
                  , a.year_in_operation
                  , a.state
                  , a.total_value
                  , b.country_id
                  , b.project_id
                  , c.isocode_3
                  , c.name
               FROM com_barchan_project a
               JOIN com_barchan_location b
                 ON b.project_id = a.id
               JOIN com_barchan_country c
                 ON c.id = b.country_id
               JOIN com_barchan_project_value_join d
                 ON a.id = d.project_id
              WHERE a.state = 1 
                AND a.sector = '$sector'
                AND ($orStr)
              ORDER 
                 BY a.total_value DESC
                  , a.category_id ASC
                  , a.name ASC
    ";
    
    0 讨论(0)
提交回复
热议问题