英文:
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...)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论