从ActiveRecord原始SQL获取类型化结果

时间:2014-08-15 18:09:51

标签: ruby postgresql activerecord

在续集中,我可以这样做:

irb(main):003:0> DB["select false"].get
=> false

返回false布尔值。我希望能够在ActiveRecord中做类似的事情:

irb(main):007:0> ActiveRecord::Base.connection.select_value "select false"
=> "f"

如您所见,它返回字符串"f"。有没有办法用ActiveRecord获取一个假布尔值? (类似地,我可能正在调用一个返回timestamptz,数组等的函数 - 我希望返回的值具有正确的类型)

我的用例:我正在调用数据库函数,想要取回一个类型化的结果而不是字符串。

5 个答案:

答案 0 :(得分:23)

虽然我毫不怀疑BjörnNilsson的答案在发布时有效,但对于Postgres 9.4和PG宝石版本0.18.2来说,它失败了。在查看PG gem文档后,我发现以下内容有效:

pg = ActiveRecord::Base.connection
@type_map ||= PG::BasicTypeMapForResults.new(pg.raw_connection)

res = pg.execute("SELECT 'abc'::TEXT AS a, 123::INTEGER AS b, 1.23::FLOAT;")
res.type_map = @type_map
res[0]
# => {"a"=>"abc", "b"=>123, "float8"=>1.23}

答案 1 :(得分:13)

非常丑陋,但你要求的是:

res = ActiveRecord::Base.connection.
select_all("select 1 as aa, false as aas, 123::varchar, Array[1,2] as xx")

# Breaks unless returned values have unique column names
res.map{|row|row.map{|col,val|res.column_types[col].type_cast val}}

# Don't care about no column names
res.map{|row|
  row.values.map.with_index{|val,idx|
    res.column_types.values[idx].type_cast val
  }
}

给出:

[[1, false, "123", [1, 2]]]

工作原理:

res.column_types

返回列名和Postgresql列类型的哈希

这是一个指向它如何工作的指针: https://github.com/rails/docrails/blob/fb8ac4f7b8487e4bb5c241dc0ba74da30f21ce9f/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb

答案 2 :(得分:6)

没有足够的声誉点来回应,但是Bjorn的回答和相关的回复在Rails 5中被破坏了。这有效:

$ cat t1315.cu
#include <stdio.h>
#define A_LARGE_NUMBER 10

struct values{
int one, two, three;
};

values *vals;
__device__ values *d_vals;

__global__ void myKernel(){
     printf("%d\n", d_vals[0].one);
}

void PopulateWithData(){
  for (int i = 0; i < A_LARGE_NUMBER; i++){
    vals[i].one = 1;
    vals[i].two = 2;
    vals[i].three = 3;
  }
}


int main(){
     vals = (values*)malloc(sizeof(values) * A_LARGE_NUMBER);
     PopulateWithData(); //populates vals with random data

     values* d_ptr;
     cudaMalloc((void**)&d_ptr, A_LARGE_NUMBER * sizeof(values));
     cudaMemcpy(d_ptr, vals, A_LARGE_NUMBER *sizeof(values),cudaMemcpyHostToDevice);
     cudaMemcpyToSymbol(d_vals, &d_ptr, sizeof(values*));
     dim3    blocksPerGrid(1,1);
     dim3    threadsPerBlock(1, 1);

    myKernel<< <blocksPerGrid, threadsPerBlock >> >();
    cudaDeviceSynchronize();
}
$ nvcc -arch=sm_35 -o t1315 t1315.cu
$ cuda-memcheck ./t1315
========= CUDA-MEMCHECK
1
========= ERROR SUMMARY: 0 errors
$

答案 3 :(得分:1)

我不知道是不是这样,但你可以创建一个没有带有假列的表格的activerecord模型:

class FunctionValue < ActiveRecord::Base
  def self.columns
    @columns ||= [];
  end

  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(
      name.to_s,
      default,
      sql_type.to_s,
      null
    )
  end

  column :value, :boolean
end

然后你可以运行:

function_value = FunctionValue.find_by_sql('select false as value').first
function_value.value

答案 4 :(得分:0)

在Rails 6中,Person.connection.select_all(sql_query).to_a

...将返回一个哈希数组,其值是类型转换的。示例:

[{"id"=>12, "name"=>"John Doe", "vip_client"=>false, "foo"=> nil, "created_at"=>2018-01-24 23:55:58 UTC}]

如果您更喜欢OpenStruct,请使用Mike的建议:

Person.connection.select_all(sql_query).to_a.map {|r| OpenStruct.new(r) }

如果您希望使用符号作为键,请在map(&:symbolize_keys)之后调用to_a