Sql 可以不使用字符串插值将变量放入查询中吗?
好的,我有一个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变量而不是字符串插值(出
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])