【问题标题】:Regex pattern doesn't work with MySQL regexp正则表达式模式不适用于 MySQL 正则表达式
【发布时间】:2019-04-16 12:27:46
【问题描述】:

我确实有下面的正则表达式可以很好地与正则表达式测试器配合使用(感谢horcrux)。但是,当我将它与 MySQL regexp 一起使用时,它不会返回任何匹配项

select query from search s where s.query regexp '^((&|^)(serviceType=SALE|propertyType=HOUSE|city=1)){1,3}$'

上面应该匹配下面

serviceType=SALE&propertyType=HOUSE&city=1
propertyType=HOUSE&serviceType=SALE&city=1
city=1&propertyType=HOUSE&serviceType=SALE
city=1&serviceType=SALE&propertyType=HOUSE
serviceType=SALE&propertyType=HOUSE
serviceType=SALE

但不是这些

serviceType=SALE&propertyType=HOUSE&city=2
propertyType=HOUSE&city=2&serviceType=SALE
city=2&propertyType=HOUSE&serviceType=SALE
serviceType=SALE&propertyType=FARM&city=1
serviceType=SALE&propertyType=UNIT
serviceType=RENTAL&propertyType=HOUSE
serviceType=RENTAL

【问题讨论】:

  • ^(serviceType=SALE|propertyType=HOUSE|city=1)(&(serviceType=SALE|propertyType=HOUSE|city=1)){0,2}$ 有效吗?错误是什么?有吗?
  • 对我来说很好:dbfiddle.uk/…
  • 感谢您的快速回复。它在测试器中有效,但不幸的是在 MySQL regexp 中仍然没有匹配项
  • 也适用于 MySQL 5.7:db-fiddle.com/f/8CYKKJ2gs1EUQ57vo1Gmyu/0
  • @zoro74 我发布的两个链接都在使用 MySQL...

标签: mysql regex regexp-like


【解决方案1】:

看起来您更希望字符串匹配所有键值对而不是任何键值对,这就是您当前的模式匹配。

尝试ANDREGEXP 操作,每个键值对一个。

s.query REGEXP '(&|^)serviceType=SALE(&|$)'
        AND s.query REGEXP '(&|^)propertyType=HOUSE(&|$)'
        AND s.query REGEXP '(&|^)city=1(&|$)'

【讨论】:

    【解决方案2】:

    不使用正则表达式的艰难解决方法,这篇文章只是为了表明它是可能的。
    诀窍是制作一个 MySQL 数字生成器并使用嵌套的 SUBSTRING_INDEX() 函数将字符串切割成标记。

    查询

     SELECT 
       separated_key_values.query
     , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               separated_key_values.separated_property
             , '='
             , 1
           )
          ,'='
         , -1
       ) AS property_key
     , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               separated_key_values.separated_property
             , '='
             , 2
           )
          ,'='
         , -1
       ) AS property_value   
    FROM (
    
    SELECT 
      DISTINCT
         search.query 
       , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               search.query
             , '&'
             , number_generator.row_number
           )
          ,'&'
         , -1
       ) separated_property
    FROM (
      SELECT 
       @row := @row + 1 AS row_number
      FROM (
        SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row1
      CROSS JOIN (
        SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row2  
      CROSS JOIN (
        SELECT @row := 0 
      ) AS init_user_params
    ) AS number_generator
    CROSS JOIN 
     search 
    
    ) AS separated_key_values
    ORDER BY 
     separated_key_values.query ASC
    

    结果

    | query                                      | property_key | property_value |
    | ------------------------------------------ | ------------ | -------------- |
    | city=1&propertyType=HOUSE&serviceType=SALE | city         | 1              |
    | city=1&propertyType=HOUSE&serviceType=SALE | serviceType  | SALE           |
    | city=1&propertyType=HOUSE&serviceType=SALE | propertyType | HOUSE          |
    | city=1&serviceType=SALE&propertyType=HOUSE | city         | 1              |
    | city=1&serviceType=SALE&propertyType=HOUSE | propertyType | HOUSE          |
    | city=1&serviceType=SALE&propertyType=HOUSE | serviceType  | SALE           |
    | city=2&propertyType=HOUSE&serviceType=SALE | serviceType  | SALE           |
    | city=2&propertyType=HOUSE&serviceType=SALE | city         | 2              |
    | city=2&propertyType=HOUSE&serviceType=SALE | propertyType | HOUSE          |
    | propertyType=HOUSE&city=2&serviceType=SALE | city         | 2              |
    | propertyType=HOUSE&city=2&serviceType=SALE | serviceType  | SALE           |
    | propertyType=HOUSE&city=2&serviceType=SALE | propertyType | HOUSE          |
    | propertyType=HOUSE&serviceType=SALE&city=1 | city         | 1              |
    | propertyType=HOUSE&serviceType=SALE&city=1 | serviceType  | SALE           |
    | propertyType=HOUSE&serviceType=SALE&city=1 | propertyType | HOUSE          |
    | serviceType=RENTAL                         | serviceType  | RENTAL         |
    | serviceType=RENTAL&propertyType=HOUSE      | propertyType | HOUSE          |
    | serviceType=RENTAL&propertyType=HOUSE      | serviceType  | RENTAL         |
    | serviceType=SALE                           | serviceType  | SALE           |
    | serviceType=SALE&propertyType=FARM&city=1  | serviceType  | SALE           |
    | serviceType=SALE&propertyType=FARM&city=1  | propertyType | FARM           |
    | serviceType=SALE&propertyType=FARM&city=1  | city         | 1              |
    | serviceType=SALE&propertyType=HOUSE        | propertyType | HOUSE          |
    | serviceType=SALE&propertyType=HOUSE        | serviceType  | SALE           |
    | serviceType=SALE&propertyType=HOUSE&city=1 | city         | 1              |
    | serviceType=SALE&propertyType=HOUSE&city=1 | propertyType | HOUSE          |
    | serviceType=SALE&propertyType=HOUSE&city=1 | serviceType  | SALE           |
    | serviceType=SALE&propertyType=HOUSE&city=2 | propertyType | HOUSE          |
    | serviceType=SALE&propertyType=HOUSE&city=2 | city         | 2              |
    | serviceType=SALE&propertyType=HOUSE&city=2 | serviceType  | SALE           |
    | serviceType=SALE&propertyType=UNIT         | propertyType | UNIT           |
    | serviceType=SALE&propertyType=UNIT         | serviceType  | SALE           |
    

    demo

    之后就像添加条件聚合一样简单。

    查询

    SELECT 
      separated_key_values.query
    
    , 
    
     (
       SUM(separated_key_values.property_key = 'serviceType') > 0
     AND
       SUM(separated_key_values.property_value = 'SALE') > 0
    
     ) AS has_serviceType_SALE
    
    , 
    
     (
       SUM(separated_key_values.property_key = 'propertyType') > 0
     AND
       SUM(separated_key_values.property_value = 'HOUSE') > 0
    
     ) AS has_propertyType_HOUSE
    
    , 
    
     (
       SUM(separated_key_values.property_key = 'City') > 0
     AND
       SUM(separated_key_values.property_value = '1') > 0
    
     )  AS has_City_1
    
    , (
    
     (
       SUM(separated_key_values.property_key = 'serviceType') > 0
     AND
       SUM(separated_key_values.property_value = 'SALE') > 0
    
     ) 
    
     + 
    
     (
       SUM(separated_key_values.property_key = 'propertyType') > 0
     AND
       SUM(separated_key_values.property_value = 'HOUSE') > 0
    
     ) 
    
     + 
    
     (
       SUM(separated_key_values.property_key = 'City') > 0
     AND
       SUM(separated_key_values.property_value = '1') > 0
    
     )   
    
      ) AS has_mask 
    
    , COUNT(*)
    
    FROM (
    SELECT 
       search_alias.query
     , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               search_alias.separated_property
             , '='
             , 1
           )
          ,'='
         , -1
       ) AS property_key
     , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               search_alias.separated_property
             , '='
             , 2
           )
          ,'='
         , -1
       ) AS property_value   
    FROM (
    
    SELECT 
      DISTINCT
         search.query 
       , SUBSTRING_INDEX(
           SUBSTRING_INDEX(
               search.query
             , '&'
             , number_generator.row_number
           )
          ,'&'
         , -1
       ) separated_property
    FROM (
      SELECT 
       @row := @row + 1 AS row_number
      FROM (
        SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row1
      CROSS JOIN (
        SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row2  
      CROSS JOIN (
        SELECT @row := 0 
      ) AS init_user_params
    ) AS number_generator
    CROSS JOIN 
     search 
    
    ) AS search_alias
    ) AS separated_key_values
    GROUP BY 
     separated_key_values.query
    HAVING 
     has_mask = COUNT(*)
    

    结果

    | query                                      | has_serviceType_SALE | has_propertyType_HOUSE | has_City_1 | has_mask | COUNT(*) |
    | ------------------------------------------ | -------------------- | ---------------------- | ---------- | -------- | -------- |
    | city=1&propertyType=HOUSE&serviceType=SALE | 1                    | 1                      | 1          | 3        | 3        |
    | city=1&serviceType=SALE&propertyType=HOUSE | 1                    | 1                      | 1          | 3        | 3        |
    | propertyType=HOUSE&serviceType=SALE&city=1 | 1                    | 1                      | 1          | 3        | 3        |
    | serviceType=SALE                           | 1                    | 0                      | 0          | 1        | 1        |
    | serviceType=SALE&propertyType=HOUSE        | 1                    | 1                      | 0          | 2        | 2        |
    | serviceType=SALE&propertyType=HOUSE&city=1 | 1                    | 1                      | 1          | 3        | 3        |
    

    demo

    您还可以将列输出放入HAVING 子句中,这样您就不会输出这些列。
    demo

    注意
    这不会在大型表上扩展,很可能正则表达式查询也不会扩展,因为很可能无法使用索引。

    一种解决方法可能是使用具有正确索引的临时表,并使用第一个查询来预填充并在索引的临时表上进行条件聚合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 1970-01-01
      • 2012-07-24
      • 1970-01-01
      • 2013-09-08
      • 2019-08-26
      • 1970-01-01
      相关资源
      最近更新 更多