如何将参数传递给 db.exec 函数?

huangapple go评论76阅读模式
英文:

How do I pass a param to db.exec

问题

考虑一下db.Exec语句,

db.Exec("INSERT INTO $1 values($2,$3,to_timestamp($4),var1,var2,var3,var4)")

^^ 这个语句是有效的,但是如果我想做这样的事情

db.Exec("INSERT INTO table_name_$1 values($2,$3,to_timestamp($4),var1,var2,var3,var4)")

它不起作用,$1被附加到表名而不是$1的值,我该如何将其添加到查询中?

英文:

Consider the db.Exec statement,

> db.Exec("INSERT INTO $1 values($2,$3,to_timestamp($4),var1,var2,var3,var4)

^^ works however if I want to do something like

>db.Exec("INSERT INTO table_name_$1 values($2,$3,to_timestamp($4),var1,var2,var3,var4)

It doesn't work, $1 gets appended to the table name instead of the values of $1, how do I add it to the query ?

答案1

得分: 2

由于您说第一个示例可以工作,一种解决方案是在之前进行字符串拼接,将完整的表名作为参数传递:

db.Exec("INSERT INTO $1 values($2,$3)", "table_name_"+tbl, "this", "that")

您还可以使用fmt.Sprintf%s手动格式化字符串,如评论中所建议的。

预处理语句

我有点惊讶您的第一个示例可以工作,因为这在Postgres中不是有效的语法。如果您使用表名作为参数创建预处理语句,它会返回语法错误:

# PREPARE fooplan (text, bool, numeric) AS
    INSERT INTO $1 VALUES($2, $3);
ERROR:  syntax error at or near "$1"
LINE 2:     INSERT INTO $1 VALUES($2, $3);

而您给出的第二个示例也将$1附加到表名中,所以库的行为是正确的:

# PREPARE fooplan (text, bool, numeric) AS
    INSERT INTO table_name_$1 VALUES($2, $3);
ERROR:  relation "table_name_$1" does not exist
LINE 2:     INSERT INTO table_name_$1 VALUES($2, $3);

因此,在您的第一个示例中,该库可能对您有利,但这可能不是您应该过于依赖的事情。

最安全的长期解决方案可能是使用fmt.Sprintf进行表名的格式化,并在Exec调用中使用该格式化后的表名:

sql := fmt.Sprintf(`INSERT INTO table_name_%s values($1,$2,to_timestamp($3))`, tbl)
db.Exec(sql, params...)
英文:

Since you say the first example works, one solution is to pass in the full table name as a parameter, doing the string concatenation beforehand:

db.Exec("INSERT INTO $1 values($2,$3)", "table_name_"+tbl, "this", "that")

You could also format the string manually with fmt.Sprintf and %s, as suggested in the comments.

Prepared statements

I am a little surprised that your first example works, as this is not valid syntax in Postgres. If you create a prepared statement with the table name as a parameter, it returns a syntax error:

# PREPARE fooplan (text, bool, numeric) AS
    INSERT INTO $1 VALUES($2, $3);
ERROR:  syntax error at or near "$1"
LINE 2:     INSERT INTO $1 VALUES($2, $3);

Whereas the second example you gave also appends $1 to the name of the table, so the library is behaving correctly:

# PREPARE fooplan (text, bool, numeric) AS
    INSERT INTO table_name_$1 VALUES($2, $3);
ERROR:  relation "table_name_$1" does not exist
LINE 2:     INSERT INTO table_name_$1 VALUES($2, $3);

So in your first example the library might be acting in your favor, but this is probably not something you should rely on too heavily.

The safest long-term solution is probably to use fmt.Sprintf, with the necessary escaping, to format the table name, and then use that in the Exec call:

sql := fmt.Sprintf(`INSERT INTO table_name_%s values($1,$2,to_timestamp($3))`, tbl)
db.Exec(sql, params...)

huangapple
  • 本文由 发表于 2014年10月19日 19:13:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/26449890.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定