Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 可以不使用字符串插值将变量放入查询中吗?_Sql_Ruby On Rails_Database_Postgresql - Fatal编程技术网

Sql 可以不使用字符串插值将变量放入查询中吗?

Sql 可以不使用字符串插值将变量放入查询中吗?,sql,ruby-on-rails,database,postgresql,Sql,Ruby On Rails,Database,Postgresql,好的,我有一个SQL请求,它使用字符串插值并运行得很好: ActiveRecord::Base.connection.execute("UPDATE my_table SET location = ST_SetSRID(ST_MakePoint('#{my_table.longitude}'::numeric, '#{my_table.latitude}'::numeric), 4326)::geography WHERE id=#{id}") 我想做的是使用SQL变量而不是字符串插值(出

好的,我有一个SQL请求,它使用字符串插值并运行得很好:

  ActiveRecord::Base.connection.execute("UPDATE my_table SET location = ST_SetSRID(ST_MakePoint('#{my_table.longitude}'::numeric, '#{my_table.latitude}'::numeric), 4326)::geography WHERE id=#{id}")
我想做的是使用SQL变量而不是字符串插值(出于安全原因(SQL注入)),但我的查询遇到了一些问题:

ActiveRecord::Base.connection.execute("UPDATE my_table SET location = ST_SetSRID(ST_MakePoint(':longitude'::numeric, ':latitude'::numeric), 4326)::geography WHERE id=#{id}", longitude: my_table.longitude, latitude: my_table.latitude)
我得到的错误是:

PG::InvalidTextRepresentation:错误:类型的输入语法无效 数字:“:经度”(ActiveRecord::StatementInvalid)


有没有办法在最后一次查询中正确使用SQL变量?

尝试使用“?”而不是插值

ActiveRecord::Base.connection.execute("UPDATE my_table SET location = ST_SetSRID(ST_MakePoint( ? , ? , 4326)::geography WHERE id= ? ", "#{my_table.longitude}::numeric", "#{my_table.latitude}::numeric)", id  )

这种方式的字符串插值非常危险,可能会将服务器打开到。而是使用来构建查询,如下所示:

my_table = MyTable.find(id)
my_table.update(location: "ST_SetSRID(ST_MakePoint('#{my_table.longitude}'::numeric, '#{my_table.latitude}'::numeric), 4326)::geography")

你为什么不使用活动记录

在您的场景中,您似乎从记录中的其他属性中获取值,以填充第三个
位置
属性

假设您的应用程序中有一个由此表支持的模型,您有两个选项:

  • 在模型上创建一个
    location
    方法,该方法根据坐标生成并返回位置。这里的一个优势是数据库中的数据重复较少,但代价是能够对生成的位置进行本机搜索,如果生成该位置的成本较高,则可能会节省成本
  • 在保存前添加一个
    回调,以便在每次保存(创建或更新)记录时生成位置。如果生成成本很高,并且您经常更新记录,这可能会导致问题。。。但是,在生成位置之前,可以通过检查坐标是否已更改来解决此问题

  • 但是,这两种解决方案都要求您在模型中编写一个方法,以根据坐标生成位置,或者至少调用一些第三方代码来为您执行此操作。

    好的,因此我尝试使用此方法(它似乎可以按预期工作):


    我不知道这样做是否有任何危险或缺陷。

    使用
    sanatize\u sql\u array
    在2020年为我工作。我认为,在这种情况下,您可以执行以下操作:

    sql=ActiveRecord::Base.sanatize\u sql\u数组([
    “更新my_table SET location=ST_SetGrid(ST_生成点('?'::numeric,'?'::numeric),4326::geography WHERE id=?”,
    我的桌子,经度,
    我的桌子,纬度,
    身份证件
    ])
    ActiveRecord::Base.connection.execute(sql)
    

    文档:

    感谢您的回答,它给了我一个
    错误数量的参数(1…2为4)(ArgumentError)
    或者先使用插值构建查询,然后将其传递到ActiveRecord::BaseString插值工作得很好(如前所示),但我不想使用它。另外,我已经在使用ActiveRecord::BaseThank,明天将尝试并报告我的结果:)好的,所以我尝试了,结果得到了一些语法错误:
    语法错误,意外',',预期=>…:地理',my_table.longitude,my_table.latitude)
    啊,看起来像是语法错误。我更新了答案以更正它(我无法测试它,但它看起来是正确的)。这个答案仍然是SQL注入安全的,因为插入的文本作为哈希值传递给updates命令,该命令将清理查询。
    @connection = ActiveRecord::Base.connection.raw_connection
    @connection.prepare('fill_column_location', "UPDATE my_table SET location = ST_SetSRID(ST_MakePoint($1::numeric, $2::numeric), 4326)::geography WHERE id=$3")
    fill_column_location = @connection.exec_prepared('fill_column_location', [my_table.longtmp, my_table.latitmp, id])