繁体   English   中英

SQL查询以逗号分隔的字符串与逗号分隔的字符串匹配?

[英]SQL query to match a comma-separated string against a comma-separated string?

下面的MySQL查询使用PHP提取$ sector(这是一个数字)和$ subsector_text(这是一个逗号分隔的字符串)。 $ subsector_text可以是一个数字或几个ID的列表,例如“ 3,4,7,9”。

  $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 a.subsector REGEXP '^{$subsector_text}[,]|[,]{$subsector_text}[,]|[,]{$subsector_text}$|^{$subsector_text}$'
          ORDER 
             BY a.total_value DESC
              , a.category_id ASC
              , a.name ASC
";

我上面的查询遇到的问题是与行:

AND a.subsector REGEXP '^{$subsector_text}[,]|[,]{$subsector_text}[,]|[,]{$subsector_text}$|^{$subsector_text}$'  

如果$ subsector_text =“ 3,4,5,9”,则仅返回$ subsector字段中包含完全为“ 3,4,5,9”的记录。

理想的结果是它将返回任何在$ subsector_text中具有任何值的记录。 例如,所有这些都应返回,但当前不返回。 此列表只是一个示例,绝不完全正确。

1,3
1,5
1,3,7,9
3,5
3,4,5,9
9
3
5
4

如何更改查询以选择$ subsector_text字符串中具有值的任何记录?

请注意:如果$ subsector_text = 11,则不应选择以下示例。

1
12
21

任何帮助将不胜感激。

在单个谓词中将逗号分隔的字符串中的任何值与另一个逗号分隔的字符串中的任何值进行匹配都是不切实际的。

您可以使用FIND_IN_SET()一次搜索一个值。

这意味着您需要多个谓词,通过分割输入$subsector_text获得的每个谓词。 因此,请拆分变量并将其映射到一系列FIND_IN_SET()调用中。

我尚未测试以下代码,但是它应该使您了解我在说什么:

$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)
...";

当然,这将强制进行表扫描,因为无法索引FIND_IN_SET()或任何其他搜索子字符串的操作。 好吧,我想您在a.state上的条件和a.sector将在应用FIND_IN_SET()条件之前使用索引来缩小搜索范围。

我了解必须使用您继承的系统的两难境地。 让您的经理知道这需要在某个时候进行重构,因为它永远不会像现在设计的那样高效或可靠。

您的方法是正确的,但需要进行一些修改。 除了尝试仅在一种条件下进行匹配(REGEXP)外,还可以创建多个通过OR条件...

例:

$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
";

解决方案是重构应用程序。 花费了几天时间,但是令人讨厌的代码消失了,并创建了一个新的子部门表。 感谢大家。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM