如何在PostgreSQL主id列上执行LIKE查询?

sco*_*ies 3 ruby sql postgresql activerecord ruby-on-rails

如果我有一个数字(例如88)并且我想在主ID列的Rails中执行LIKE查询以返回在ID结尾处包含该数字的所有记录(IE:88,288等),我该怎么办?这是生成结果的代码,在SQLLite中可以正常工作:

@item = Item.where("id like ?", "88").all
Run Code Online (Sandbox Code Playgroud)

在PostgreSQL中,我遇到了这个错误:

PG::Error: ERROR:  operator does not exist: integer ~~ unknown
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?我已经尝试将数字转换为字符串,但这似乎也不起作用.

jef*_*unt 8

简单的案例

LIKE用于字符串/文本类型.由于您的主键是整数,因此您应该使用数学运算.

id当除以100时,使用modulo获取值的其余部分.

Item.where("id % 100 = 88")
Run Code Online (Sandbox Code Playgroud)

这将返回列Item以其id结尾的记录88

1288
1488
1238872388
862388
Run Code Online (Sandbox Code Playgroud)

等等...

匹配最后两位数的任意组

如果您要动态执行此操作(例如,匹配任意两位数字,但您知道它总是两位数),您可以执行以下操作:

Item.where(["id % 100 = ?", last_two_digits)
Run Code Online (Sandbox Code Playgroud)

匹配任何一组或多个最终数字

如果您想匹配任意数量的数字,只要它们始终是最终数字(而不是id字段中其他位置出现的数字),您可以在模型上添加自定义方法.就像是:

class Item < ActiveRecord

  ...

  def find_by_final_digits(num_digits, digit_pattern)
    # Where 'num_digits' is the number of final digits to match
    # and `digit_pattern` is the set of final digits you're looking fo

    Item.where(["id % ? = ?", 10**num_digits, digit_pattern])
  end

  ...

end
Run Code Online (Sandbox Code Playgroud)

使用此方法,您可以找到id以...结尾的值88:

Item.find_by_final_digits(2, 88)
Run Code Online (Sandbox Code Playgroud)

匹配任何长度的最终数字范围

比方说,你希望找到所有id与数字最终值之间的 0912,无论出于何种原因.也许它们代表了你正在寻找的一些特殊代码范围.为此,您可以使用另一种自定义方法来使用Postgres BETWEEN来查找范围.

def find_by_final_digit_range(num_digits, start_of_range, end_of_range)
  Item.where(["id % ? BETWEEN ? AND ?", 10**num_digits, start_of_range, end_of_range)
end
Run Code Online (Sandbox Code Playgroud)

......可以使用以下方式调用:

Item.find_by_final_digit_range(2, 9, 12)
Run Code Online (Sandbox Code Playgroud)

......当然,这只是有点疯狂,而且可能有点过分.

  • 如果你问因为你在开发中使用SQLite,而在生产中使用Postgres,那么让Postgres在开发中工作真的不是那么多.如果您开始在应用程序中编写任何自定义SQL,您将希望在两个环境中使用相同的风格,以避免在尝试部署时出现意外情况. (3认同)
  • 在开发和生产中使用Postgres的+1.给你带来很多麻烦.查看[这个相关问题](http://stackoverflow.com/questions/11249059/generic-ruby-solution-for-sqlite3-like-or-postgresql-ilike)作为另一个例子,为什么混合是一个坏主意. (2认同)

Erw*_*ter 5

LIKE运算符仅适用于字符串类型。
模运算符%用于您要执行的操作:

@item = Item.where("(id % 100) = ?", "88").all
Run Code Online (Sandbox Code Playgroud)

我怀疑它在 SQLite 中“有效”,即使它将数字类型强制转换为字符串。不引导%模式是行不通的。
-> sqlfiddle 演示

投射到任意长度并按您的意图text使用:LIKE

@item = Item.where("(id::text LIKE ('%'::text || ?)", "'12345'").all
Run Code Online (Sandbox Code Playgroud)

或者,数学上:

@item = Item.where("(id % 10^(length(?)) = ?", "'12345'", "12345").all
Run Code Online (Sandbox Code Playgroud)


Rub*_*cer 5

基于Erwin的答案:
这是一个非常老的问题,但是如果有人需要它,可以使用::textcast 使用一个非常简单的答案:

Item.where("(id::text LIKE ?)", "%#{numeric_variable}").all
Run Code Online (Sandbox Code Playgroud)

这样,您可以在字符串中的任意位置找到数字。仅当您希望数字位于字符串末尾时,才应在左侧
使用%通配符。如果您希望数字在字符串中的任何位置,也
%在右侧使用通配符。