2010-06-06 11 views
13

Chcę wykonać konkatenację ciągów po stronie bazy danych w zapytaniu Rails i zrobić to w sposób niezależny od bazy danych.Niezależna od bazy danych konwersja ciągów SQL w szynach

SQL-92 określa podwójny pasek (||) jako operator konkatenacji. Niestety wygląda na to, że MS SQL Server go nie obsługuje; zamiast tego używa +.

Zgaduję, że abstrakcja gramatyki SQL Railsów rozwiązała już problem operatora specyficznego dla db. Jeśli istnieje, jak go używać?

Odpowiedz

10

Miałem ten sam problem i nigdy nie wymyśliłem niczego, co zostało wbudowane w Rails. Więc napisałem tę małą metodę.

# 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 

myślę naprawdę ktoś powinien napisać jakiś plugin SQL pomocnika, który mógłby automatycznie sformatować prostych wyrażeń SQL w oparciu używając prawidłowych funkcji lub operatorów dla bieżącego adaptera. Może sam to napiszę.

+0

Myślę, że jeśli to będzie istniało, będziesz tym, który to napisze :-P –

+1

FYI, napisałem to http://github.com/adamcrown/port-a-query. Nie ma jeszcze zbyt wiele, ale radzi sobie z konkatenacją w MySQL i SQLite – aNoble

0

Jeśli chcesz, aby coś Railsów było neutralnych, będziesz musiał zwrócić wartości, które chcesz połączyć, i zrobić to po dostarczeniu danych do szyn (lub zrobić to na szynach, zanim podasz je do bazy danych).

Wygląda na to, że Mysql używa CONCAT(), Postgres ||, Oracle CONCAT() lub ||, T-SQL +.

Wszelkie abstrakcje tego samego szyn będą musiały odbywać się w punkcie, w którym można po prostu robić łączenie za pomocą zwykłej Ruby, lub zupełnie źle rozumiałem pytanie.

+0

To, czego szukam, to sposób na dostęp do różnych metod łączenia (które wymieniono) w sposób niezależny od bazy danych. Wyobrażam sobie coś w Railsach, które pobierają dwa ciągi (wyrażenia), wiążą je razem z operatorem/funkcją konkatenacji db, a następnie zwraca pojedynczy ciąg znaków. Wezmę ten ciąg, a następnie użyję go w mojej instrukcji SQL. –

6

Nie otrzymał jeszcze dużego wykorzystania, ale napisałem następujący kod, który wydaje się rozwiązać problem. Ta małpa-łata adaptery mieć sposób, aby go wspierać:

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 

Z tego powinieneś być w stanie wykonać następujące czynności w kodzie:

class User < ActiveRecord::Base 

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

end 

ten wyprowadza następujące zapytanie SQL na zasadzie SQL 92 danych (Oracle SQLite PostgreSQL)

SELECT * FROM users WHERE first_name || last_name = ? 

MySQL wyprowadza:

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

Dla SQL Server wyprowadza

SELECT * FROM users WHERE first_name + last_name = ? 

Oczywiście można rozszerzyć tę koncepcję do innych adapterów baz danych.

Powiązane problemy