簡體   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