在我的应用程序的安装脚本中,我检查数据库是否包含任何表。如果数据库为空,我有DML和DDL SQL脚本,我想运行。
从单独的.sql文件中读取SQL并不重要,所以我现在直接把它直接放到两个字符串中 - 一个用于DDL,一个用于DML - 并连接它们。
我现在的问题是,当我尝试运行脚本以生成表并使用.Exec(sqlStr)将数据插入其中时,我现在遇到此错误:
"pq: cannot insert multiple commands into a prepared statement"
我当然可以做一个解决方法。类似的东西:
sqlStr := sqlDML + sqlDDL
sqlStmtSlice := strings.Split(sqlStr, ";")
for i:= 0; i < len(sqlStmtSlice) i++ {
// Exec() each individual statement!
}
但是,我不确定我是否喜欢这种方法。当然,必须有更好的方法从文件加载SQL脚本并执行整批,对吧?你知道吗?
聚苯乙烯。我使用PostgreSQL驱动程序用于Go,但我认为这没有任何区别。
修改:
由于当时似乎没有更好的解决方案来完成这项工作,我对上面的伪代码做了一些改进,经过测试并且似乎工作得很好:
tx, err := db.Begin()
sqlStr := fmt.Sprintf(sqlDML + sqlDDL)
sqlStmtSlice := strings.Split(sqlStr, ";\r")
if err != nil {
return err
}
defer func() {
_ = tx.Rollback()
}()
for _, q := range sqlStmtSlice {
_, err := tx.Exec(q)
if err != nil {
return err
}
}
err = tx.Commit()
答案 0 :(得分:4)
据我所知,如果不允许多个语句查询,则不是一个更好的方法。它与您正在使用的驱动程序无关,因为这是database/sql
程序包限制。辩论它是否是一个好的设计是另一个问题(而且我确定已经有很多)。
在备选方面,您可以使用SQL Schema Migration工具或使用它们的灵感。一般惯例是使用语义惰性标记,例如注释,并围绕这些标记分开。
对于golang中的示例,您可以看到:
免责声明:我是漫步者的开发者。那就是说,你应该明确地看看 goose ,这真的很酷。
答案 1 :(得分:1)
一段时间以来一直在努力解决同样的问题。我需要它的原因略有不同(在运行测试之前初始化数据库)。
正如Elwinar已经提到的,database/sql
包不允许这样做。我克服这个问题的方法是创建一个python脚本(让它调用它sql_runner.py
)来执行一个文件,然后运行一个go exec命令来执行python脚本(别忘了让它可执行)。
这是一个运行sql文件的python命令:cursor.execute(open("setting_up.sql"), "r").read())
运行此文件的Go代码的一部分:
cmd := exec.Command("sql.py")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Println(cmd.Run())