【问题标题】:How do you write a case insensitive query for both MySQL and Postgres?您如何为 MySQL 和 Postgres 编写不区分大小写的查询?
【发布时间】:2010-09-17 05:35:43
【问题描述】:

我在本地运行 MySQL 数据库进行开发,但部署到使用 Postgres 的 Heroku。 Heroku 几乎可以处理所有事情,但我不区分大小写的 Like 语句变得区分大小写。我可以使用 iLike 语句,但我的本地 MySQL 数据库无法处理。

编写与 MySQL 和 Postgres 兼容的不区分大小写查询的最佳方法是什么?或者我是否需要根据我的应用正在与之通信的数据库编写单独的 Like 和 iLike 语句?

【问题讨论】:

  • 如果您在生产中使用 Postgres,也可以在本地使用 Postgres。这不会是您遇到的第一个问题,这也意味着您无法利用 Postgres 特有的任何东西。
  • 也许你写这个问题的时候很难安装和运行 Postgres,但是现在使用 Docker 运行 Postgres 很容易

标签: mysql ruby-on-rails database postgresql heroku


【解决方案1】:

这个故事的寓意是:不要使用不同的软件堆栈进行开发和生产。从不。

您最终会遇到无法在开发中重现的错误;你的测试将毫无价值。只是不要这样做。

使用不同的数据库引擎是不可能的 - 将有更多的情况下它的行为与 LIKE 不同(另外,您是否检查过数据库使用的排序规则?它们在每种情况下都相同吗?如果不是,你可以忘记在 varchar 列上的 ORDER BY 工作相同)

【讨论】:

  • +1 为道德提升,谢谢。不过,说真的,这是正确的,而且比任何“只回答问题”的答案都要好得多。虽然我一般讨厌这些故事答案的寓意,但在这种情况下它做得很好。
  • AR/AM 的全部意义在于允许您在开发和生产中使用不同的数据库后端。在我看来,这里的失败在于 AR/AM 如何生成查询。
  • @christopher Maujean:请参阅 joelonsoftware.com/articles/LeakyAbstractions.html 了解为什么这是一个坏主意。
  • 我希望我不是在这里拖钓,但我对此回应有两个反对意见。首先,这不是问题的答案。其次,在开发和生产中使用不同的数据库不是主要问题。真正的问题是没有使用抽象来执行不区分大小写的查询。理想情况下,活动记录将提供此功能,而无需深入了解供应商特定的 SQL。我的建议是看看stackoverflow.com/questions/2220423/…中的建议
  • @MarkR 当然,您的建议非常合理,但 OP 的问题仍然有效。编写符合 SQL 且独立于平台的查询具有一定的价值,特别是如果将来可能需要将系统移植到另一个数据库。显然,在这种情况下没有完美的答案。
【解决方案2】:
select * from foo where upper(bar) = upper(?);

如果在调用者中将参数设置为大写,则可以避免第二次函数调用。

【讨论】:

  • 你也可以确保它的上部:WHERE UPPER(bar) = UPPER(?)
  • 我不能 100% 确定,但我记得这不会使用 foo 上可能存在的任何索引,因为它无法根据索引扫描函数的返回值。
  • @Richo:但如果需要,您可以在upper(bar) 创建索引:postgresql.org/docs/current/interactive/sql-createindex.html
  • 我建议传递给 Arel 的参数在 Ruby 中大写,这样就不需要 SQL 进行额外的处理。 where("UPPER(bar) = ?", parameter.upcase)
【解决方案3】:

使用阿雷尔:

Author.where(Author.arel_table[:name].matches("%foo%"))

matches 将对 Postgres 使用 ILIKE 运算符,对其他所有内容使用 LIKE

【讨论】:

  • 希望我能给超过+1...我从来不知道Arel 可以做到这一点!也许是因为它几乎完全没有记录?嗯……
  • 是的 --- 这在任何地方都有记录吗?
【解决方案4】:

在 postgres 中,你可以这样做:

SELECT whatever FROM mytable WHERE something ILIKE 'match this';

我不确定是否有 MySQL 的等价物,但你总是可以这样做,这有点难看,但应该在 MySQL 和 postgres 中都可以工作:

SELECT whatever FROM mytable WHERE UPPER(something) = UPPER('match this');

【讨论】:

    【解决方案5】:

    有几个答案,没有一个是很满意的。

    • LOWER(bar) = LOWER(?) 将在 MySQL 和 Postgres 上工作,但可能在 MySQL 上表现糟糕:MySQL 不会由于 LOWER 功能,使用它的索引。在 Postgres 上,您可以添加功能索引(在 LOWER(bar) 上),但 MySQL 不支持。
    • MySQL 将(除非您设置了区分大小写的collation)自动进行不区分大小写的匹配,并使用其索引。 (bar = ?)。
    • 从数据库外部的代码中,维护 barbar_lower 字段,其中 bar_lower 包含 lower(bar) 的结果。 (这也可以使用数据库触发器)。 (请参阅Drupal 上对此解决方案的讨论)。这很笨拙,但至少在几乎每个数据库上都以相同的方式运行。

    【讨论】:

    • 感谢第 2 点,我发现默认情况下它确实不区分大小写。
    【解决方案6】:

    REGEXP 不区分大小写(除非与 BINARY 一起使用),并且可以像这样使用...

        SELECT id FROM person WHERE name REGEXP 'john';
    

    ...匹配 'John'、'JOHN'、'john' 等。

    【讨论】:

    • 这太棒了!我可以使用| 来拥有多个搜索关键字。
    • 虽然正则表达式非常通用,但请注意它们非常慢,您会在较大的数据集或慢速服务器上注意到这一点
    【解决方案7】:

    如果您使用的是 PostgreSQL 8.4,则可以使用 citext 模块创建不区分大小写的文本字段。

    【讨论】:

    【解决方案8】:
    【解决方案9】:

    您还可以考虑查看searchlogic 插件,它为您执行LIKE/ILIKE 开关。

    【讨论】:

      【解决方案10】:

      如果你想匹配一个块中的子字符串,你也可以在 postgres 中使用 ~*。 ~ 匹配区分大小写的子字符串,~* 不区分大小写的子字符串。这是一个缓慢的操作,但我是否会发现它对搜索有用。

      Select * from table where column ~* 'UnEvEn TeXt';
      Select * from table where column ~ 'Uneven text';
      

      两者都会点击“这里有一些不均匀的文字” 只有前者会点击“Some UNEVEN TEXT here”

      【讨论】:

        【解决方案11】:

        最好转换为上层,因为它涵盖了 3 个最常用的 Rails 数据库后端的兼容语法。 PostgreSQL、MySQL 和 SQLite 都支持这种语法。它有一个(小)缺点,您必须在应用程序或条件字符串中将搜索字符串大写,这使它有点难看,但我认为您获得的兼容性使其值得。

        MySQL 和 SQLite3 都有一个不区分大小写的 LIKE 运算符。只有 PostgreSQL 有一个区分大小写的 LIKE 运算符和一个特定于 PostgreSQL(根据手册)的 ILIKE 运算符,用于不区分大小写的搜索。您可以在 Rails 应用程序的条件中指定 ILIKE 而不是 LIKE,但请注意,该应用程序将停止在 MySQL 或 SQLite 下工作。

        第三个选项可能是检查您正在使用的数据库引擎并相应地修改搜索字符串。这可能通过侵入/monkeypatching ActiveRecord 的连接适配器来更好地完成,并让 PostgreSQL 适配器在查询执行之前修改查询字符串以用“LIKE”替换“ILIKE”。然而,这个解决方案是最复杂的,并且考虑到像大写这两个术语这样更简单的方法,我认为这不值得努力(尽管这样做你会得到很多布朗尼积分)。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-03
        • 2014-07-19
        • 1970-01-01
        • 2011-08-22
        相关资源
        最近更新 更多