Database-independent SQL String Concatenation in Rails

后端 未结 3 1765
难免孤独
难免孤独 2020-12-10 04:03

I want to do a database-side string concatenation in a Rails query, and do it in database-independent way.

SQL-92 specifies double-bar (||) as the conca

3条回答
  •  长情又很酷
    2020-12-10 04:36

    It hasn't received much usage yet but I wrote the following code which seems to solve the problem. This monkey-patches the adapters to have a method to support it:

    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
    

    With this you should be able to do the following in your code:

    class User < ActiveRecord::Base
    
      def self.find_by_name(name)
        where("#{connection.concat('first_name', 'last_name')} = ?", name)
      end
    
    end
    

    This outputs the following SQL query on a SQL-92 database (Oracle, SQLite, PostgreSQL):

    SELECT * FROM users WHERE first_name || last_name = ?
    

    For MySQL it outputs:

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

    For SQL Server it outputs

    SELECT * FROM users WHERE first_name + last_name = ?
    

    Obviously you could extend this concept to other database adapters.

提交回复
热议问题