2010-06-06 9 views
13

Quiero hacer una concatenación de cadenas en el lado de la base de datos en una consulta de Rails, y hacerlo de manera independiente de la base de datos.Concatenación de cadenas de SQL independiente de la base de datos en Rails

SQL-92 especifica la barra doble (||) como el operador de concatenación. Desafortunadamente, parece que MS SQL Server no lo admite; usa en su lugar +.

Supongo que la abstracción gramatical SQL de Rails ya ha resuelto el problema del operador específico de db. Si existe, ¿cómo lo uso?

Respuesta

10

Tuve el mismo problema y nunca se me ocurrió nada integrado en Rails. Entonces escribí este pequeño método.

# 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 

Estoy pensando en alguien realmente debería escribir una especie de complemento de ayuda de SQL que podrían dar formato automáticamente las expresiones SQL simples basados ​​usando las funciones u operadores correctos para el adaptador de corriente. Tal vez voy a escribir uno yo mismo.

+0

Creo que si va a existir, usted será el que lo escriba :-P –

+1

FYI, lo escribí http://github.com/adamcrown/port-a-query. Aún no hay mucho, pero maneja la concatenación en MySQL y SQLite – aNoble

0

Si desea que algo sea neutral, necesitará devolver los valores que desea concatenar y hacer eso una vez que los datos se han enviado a los rieles (o hacerlo en rieles antes de entregarlos a la base de datos).

Parece que Mysql usa CONCAT(), Postgres ||, Oracle CONCAT() o ||, T-SQL +.

Cualquier abstracción de rieles de la misma tendría que tener lugar en un punto en el que podría estar haciendo concatenación utilizando Ruby regular, o he entendido mal la pregunta.

+0

Lo que estoy buscando es una forma de acceder a los diversos métodos de concatenación (que enumeró) de forma independiente de db. Estoy imaginando algo en Rails que toma dos cadenas (expresiones), las vincula con el operador/función de concatenación específica de db y luego devuelve una sola cadena. Tomaré esa cadena y luego la usaré en mi declaración de SQL. –

6

Aún no ha recibido mucho uso pero escribí el siguiente código que parece resolver el problema. Este mono-parches de los adaptadores de disponer de un método para apoyarlo:

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 

Con esto, usted debe ser capaz de hacer lo siguiente en su código:

class User < ActiveRecord::Base 

    def self.find_by_name(name) 
    where("#{connection.concat('first_name', 'last_name')} = ?", name) 
    end 

end 

Esto da salida a la siguiente consulta SQL en una base de datos SQL-92 (Oracle, SQLite, PostgreSQL):

SELECT * FROM users WHERE first_name || last_name = ? 

Para MySQL se da salida:

SELECT * FROM users WHERE CONCAT(first_name, last_name) = ? 

Para SQL Server emite

SELECT * FROM users WHERE first_name + last_name = ? 

Obviamente se podría extender este concepto a otros adaptadores de base de datos.

Cuestiones relacionadas