【发布时间】:2011-02-28 12:11:13
【问题描述】:
我想在 Rails 查询中进行数据库端字符串连接,并以独立于数据库的方式进行。
SQL-92 指定双杠 (||) 作为连接运算符。不幸的是,MS SQL Server 似乎不支持它;它改用+。
我猜 Rails 的 SQL 语法抽象已经解决了特定于 db 的运算符问题。如果确实存在,我该如何使用它?
【问题讨论】:
标签: sql sql-server ruby-on-rails ruby concatenation
我想在 Rails 查询中进行数据库端字符串连接,并以独立于数据库的方式进行。
SQL-92 指定双杠 (||) 作为连接运算符。不幸的是,MS SQL Server 似乎不支持它;它改用+。
我猜 Rails 的 SQL 语法抽象已经解决了特定于 db 的运算符问题。如果确实存在,我该如何使用它?
【问题讨论】:
标签: sql sql-server ruby-on-rails ruby concatenation
我遇到了同样的问题,但从来没有想出任何内置到 Rails 中的东西。所以我写了这个小方法。
# Symbols should be used for field names, everything else will be quoted as a string
def db_concat(*args)
adapter = configurations[RAILS_ENV]['adapter'].to_sym
args.map!{ |arg| arg.class==Symbol ? arg.to_s : "'#{arg}'" }
case adapter
when :mysql
"CONCAT(#{args.join(',')})"
when :sqlserver
args.join('+')
else
args.join('||')
end
end
我认为应该有人真正编写某种 SQL 帮助插件,该插件可以基于使用当前适配器的正确函数或运算符自动格式化简单的 SQL 表达式。也许我会自己写一个。
【讨论】:
它尚未得到太多使用,但我编写了以下代码似乎可以解决问题。这个猴子对适配器进行了修补,以获得支持它的方法:
module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
# Will return the given strings as a SQL concationation. By default
# uses the SQL-92 syntax:
#
# concat('foo', 'bar') -> "foo || bar"
def concat(*args)
args * " || "
end
end
class AbstractMysqlAdapter < AbstractAdapter
# Will return the given strings as a SQL concationation.
# Uses MySQL format:
#
# concat('foo', 'bar') -> "CONCAT(foo, bar)"
def concat(*args)
"CONCAT(#{args * ', '})"
end
end
class SQLServerAdapter < AbstractAdapter
# Will return the given strings as a SQL concationation.
# Uses MS-SQL format:
#
# concat('foo', 'bar') -> foo + bar
def concat(*args)
args * ' + '
end
end
end
end
有了这个,你应该能够在你的代码中执行以下操作:
class User < ActiveRecord::Base
def self.find_by_name(name)
where("#{connection.concat('first_name', 'last_name')} = ?", name)
end
end
这会在 SQL-92 数据库(Oracle、SQLite、PostgreSQL)上输出以下 SQL 查询:
SELECT * FROM users WHERE first_name || last_name = ?
对于 MySQL,它输出:
SELECT * FROM users WHERE CONCAT(first_name, last_name) = ?
对于 SQL Server,它输出
SELECT * FROM users WHERE first_name + last_name = ?
显然您可以将此概念扩展到其他数据库适配器。
【讨论】:
如果你想要 Rails 中立的东西,你将需要返回你想要连接的值,并在数据传送到 rails 后执行此操作(或在将其提供给数据库之前在 rails 中执行此操作)。
Mysql 好像使用了 CONCAT()、Postgres ||、Oracle CONCAT() 或者 ||、T-SQL +。
任何相同的 Rails 抽象都必须发生在您可以使用常规 Ruby 进行连接的地方,否则我完全误解了这个问题。
【讨论】: