【问题标题】:Complex SQL query with regular expression使用正则表达式的复杂 SQL 查询
【发布时间】:2017-06-13 15:04:40
【问题描述】:

我需要编写一个非常复杂的 mysql 查询,它考虑了许多条件。我会尽力解释它。 我们有一个包含公司信息的表格。有另一个表保存这些公司的约会,另一个表保存这些约会的各种描述。我需要结合所有 3 个表格并根据用户的搜索参数带来结果。 表格是这样的

  • “公司”表包含许多详细信息,例如公司名称、邮编、地址、电话等。

  • “联系人”表有一个与公司 ID 对应的“comp_id”单元格、一个名为“entrydate”的时间戳条目(它是创建联系人的时间)和一个“约会”单元格,用于表示约会何时被设置。 它还有一个 'status' 单元格,它只是 'contact_status' 表的 id,其中包含约会的描述(例如:紧急、低优先级等)

现在问题来了。 SQL是基于复杂的搜索表单创建的。由于公司内部有不同的部门,一些用户对数据库数据的访问权限不同......例如邮政编码的搜索能力必须受到限制,各种状态也是如此的任命。 一些用户可以看到一定范围的邮政编码,或/和只有特定的联系状态。因为邮编太多,参数以“..and ZIP code doesn't start with 558”的for形式给我。因此,例如以 55 开头的 zip 被(某些搜索)接受,但如果它们以 558 开头则不被接受。所有这些都是通过 php 完成的。我可以创建 if/else 语句来为最终的 mysql 查询创建 AND 或 WHERE 行。到目前为止,我“制作”了这个查询:

SELECT DISTINCT 
    a.id, a.comp_name, a.comp_zip, a.comp_addr
    c.description as status, b.appointdate as appointement
    FROM
      Companies a
      LEFT JOIN Contacts b ON b.comp_id = a.id
      LEFT JOIN Contact_Status c ON c.id = b.status
      WHERE a.caller_id = '45346'
      AND (b.status NOT IN ( '2', '3', '5' ) OR b.status IS NULL)
      AND (a.comp_zip NOT REGEXP '50(.*)|54(.*)|55(.*)|532(.*)|668(.*)|669(.*)')
      ORDER BY a.id
            DESC

但这并没有带来正确的结果。例如,假设一家公司的邮政编码为 77554。它不会带上这家公司,因为正则表达式可能是错误的。它识别出拉链内的 55,而忽略了这家公司。 我认为正确的方法可能是:'^50(.*)|^54(.*)|^55(.*)....' 但我不确定....我需要确定这一点。这就是我创建这篇文章的原因。我在网上找不到相关信息。

使用 reg expr 检查多个“喜欢”值的正确方法是什么。以某事开头? 谢谢

【问题讨论】:

  • 这是一个有趣的问题。您从条件a.caller_id = '45346' AND (b.status NOT IN ( '2', '3', '5' ) OR b.status IS NULL) 中获得了多少行?是否可以在没有邮政编码过滤器的情况下获取数据,然后在应用程序(而不是数据库)层上解析它?
  • 另外,我有一个包含 43000 个邮政编码的数据库,我检查了这两个查询 - select SQL_NO_CACHE * from zip_code where zip like "50%" or zip like "55%" or zip like "77%"select SQL_NO_CACHE * from zip_code where zip regexp ('^(50(.*)|55(.*)|77(.*))')Like 查询的工作速度比 regexp 查询快 10 倍。
  • 因为我使用 jquery 数据表来显示数据,并计算 SQL 行以获取数据库中的最终条目,所以我不能在 SQL 之后做“事情”。我需要一切都在mysql里面。我也尝试了“不喜欢”的解决方案,但我仍然不确定它是否正确……而且因为我信任 reg expr。更多我想找到基于此的解决方案。 30 万家公司中的“a.caller_id 等”参数通常只带回 0-5000 个条目。所以它并不可怕。它作为查询速度很快。顺便说一句,b.status IS NULL 也将带来没有约会设置的公司。
  • 这很重要,因为我们想带上那些有或没有预约的公司,而且他们的邮政编码不是“等等等等。” ps:DISTINCT 可能是不必要的,但最好是安全而不是抱歉

标签: php mysql regex join


【解决方案1】:

您实际上需要在 REGEXP 的开头添加一个^,并将内容包装在() 中。试试看:^(50(.*)|54(.*)|55(.*)|532(.*)|668(.*)|669(.*))

^() 将确保值包含的值开头。

为清楚起见,这将是您的查询:

SELECT DISTINCT 
    a.id, a.comp_name, a.comp_zip, a.comp_addr
    c.description as status, b.appointdate as appointement
FROM
  Companies a
  LEFT JOIN Contacts b ON b.comp_id = a.id
  LEFT JOIN Contact_Status c ON c.id = b.status
  WHERE a.caller_id = '45346'
  AND (b.status NOT IN ( '2', '3', '5' ) OR b.status IS NULL)
  AND (
     a.comp_zip NOT 
     REGEXP '^(50(.*)|54(.*)|55(.*)|532(.*)|668(.*)|669(.*))' -- changed this part
  ) 
  ORDER BY a.id DESC

【讨论】:

  • hmm 失败:SELECT * FROM Companies WHERE comp_zip LIKE '77%' AND comp_zip NOT REGEXP ^(50(.*)|54(.*)|55(.*) |532(.*)|668(.*)|669(.*)) ,从 '^(50.....' 开始的错误
  • @user1033882 您缺少正则表达式周围的单个 qoutes。应该是REGEXP '^(50(.*)|54(.*)|55(.*)|532(.*)|668(.*)|669(.*))'
  • 谢谢,你是对的......我想 3 小时试图解决这个问题让我头疼
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 2022-11-05
  • 2017-06-18
  • 2015-02-21
  • 2015-12-20
  • 1970-01-01
  • 2014-07-17
  • 2017-05-13
相关资源
最近更新 更多