Независимая от базы данных конкатенация строк SQL в Rails - PullRequest
13 голосов
/ 07 июня 2010

Я хочу выполнить конкатенацию строк на стороне базы данных в запросе Rails и сделать это независимо от базы данных.

SQL-92 указывает на двойную черту (||) в качестве оператора конкатенации. К сожалению, похоже, что MS SQL Server не поддерживает его; вместо него используется +.

Я предполагаю, что абстракция грамматики SQL в Rails уже решила проблему, связанную с db-оператором. Если он существует, как мне его использовать?

Ответы [ 3 ]

10 голосов
/ 30 июля 2010

У меня была такая же проблема, и я никогда не придумывал ничего, что было встроено в 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 на основе правильных функций или операторов для текущего адаптера. Может быть, я сам напишу.

6 голосов
/ 20 сентября 2012

Он пока не получил широкого применения, но я написал следующий код, который, похоже, решает проблему.Эта обезьяна исправляет адаптеры, чтобы иметь метод для его поддержки:

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-запрос к базе данных SQL-92 (Oracle, SQLite, PostgreSQL):

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 = ?

Очевидно, что вы можете распространить эту концепцию на другие адаптеры баз данных.

0 голосов
/ 07 июня 2010

Если вы хотите что-то нейтральное в Rails, вам нужно будет вернуть значения, которые вы хотите объединить, и сделать это, как только данные будут доставлены в рельсы (или сделать это в рельсах, прежде чем передать их в базу данных).

Похоже, что Mysql использует CONCAT (), Postgres ||, Oracle CONCAT () или ||, T-SQL +.

Любая такая же абстракция рельсов должна происходить в точке, где вы могли бы просто выполнять конкатенацию с использованием обычного Ruby, или я совершенно неправильно понял вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...