【问题标题】:Database-independent SQL String Concatenation in RailsRails 中独立于数据库的 SQL 字符串连接
【发布时间】:2011-02-28 12:11:13
【问题描述】:

我想在 Rails 查询中进行数据库端字符串连接,并以独立于数据库的方式进行。

SQL-92 指定双杠 (||) 作为连接运算符。不幸的是,MS SQL Server 似乎不支持它;它改用+

我猜 Rails 的 SQL 语法抽象已经解决了特定于 db 的运算符问题。如果确实存在,我该如何使用它?

【问题讨论】:

    标签: sql sql-server ruby-on-rails ruby concatenation


    【解决方案1】:

    我遇到了同样的问题,但从来没有想出任何内置到 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 表达式。也许我会自己写一个。

    【讨论】:

    • 我认为如果它存在,你将成为编写它的人:-P
    • 仅供参考,我确实写了 github.com/adamcrown/port-a-query 。它还没有太多功能,但它确实可以处理 MySQL 和 SQLite 中的连接
    【解决方案2】:

    它尚未得到太多使用,但我编写了以下代码似乎可以解决问题。这个猴子对适配器进行了修补,以获得支持它的方法:

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

    显然您可以将此概念扩展到其他数据库适配器。

    【讨论】:

      【解决方案3】:

      如果你想要 Rails 中立的东西,你将需要返回你想要连接的值,并在数据传送到 rails 后执行此操作(或在将其提供给数据库之前在 rails 中执行此操作)。

      Mysql 好像使用了 CONCAT()、Postgres ||、Oracle CONCAT() 或者 ||、T-SQL +。

      任何相同的 Rails 抽象都必须发生在您可以使用常规 Ruby 进行连接的地方,否则我完全误解了这个问题。

      【讨论】:

      • 我正在寻找的是一种以独立于数据库的方式访问各种连接方法(您列出的)的方法。我正在想象 Rails 中的一些东西,它接受两个字符串(表达式),将它们与特定于 db 的连接运算符/函数联系在一起,然后返回一个字符串。我将获取该字符串,然后在我的 SQL 语句中使用它。
      猜你喜欢
      • 2015-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 2019-04-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多