我正在使用Slick Plain Sql queries来删除MariaDb数据库中的所有表。
这是我正在使用的代码:
import dbConfig.profile.api._
val databaseName : String
import slick.jdbc.SetParameter
implicit val SetString = SetParameter[Vector[String]](
(s, pp) => pp.setString(s(pp.pos))
)
def dropTables = {
val tablesToDrop : DBIO[Vector[String]] =
sql"SELECT concat(table_name) FROM information_schema.tables WHERE table_schema = '#$databaseName';".as[String]
val dbio : DBIO[Vector[String]] = for {
table <- tablesToDrop
_ <- sqlu"DROP TABLE IF EXISTS '$table';"
} yield table
val future = dbConfig.db.run(dbio)
val r = Await.result(future.andThen { case _ => dbConfig.db.close },
Duration.Inf)
}
它成功获取了要删除的表的列表,但是由于Exception in thread "main" java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
代码,我怀疑是错误Setparameter
。
有什么想法吗?
这是一个使用地图的版本(我猜它们应该是flatMaps?):
val tablesToDrop : DBIO[Vector[String]] = sql"SELECT concat(table_name) FROM information_schema.tables WHERE table_schema = '#$databaseName';".as[String]
def dropTable(tableName: String) : DBIO[Vector[String]] = sql"DROP TABLE IF EXISTS '$tableName';".as[String]
val dt = tablesToDrop.map(dbio => dbio.map(dropTable))
此命令运行无误,但不会删除表。这是日志:
DEBUG slick.basic.BasicBackend.action - #1: StreamingResultAction [SELECT concat(table_name) FROM information_schema.tables WHERE table_schema = 'altairdb';]
DEBUG slick.jdbc.JdbcBackend.statement - Preparing statement: SELECT concat(table_name) FROM information_schema.tables WHERE table_schema = 'altairdb';
DEBUG slick.jdbc.JdbcBackend.benchmark - Execution of prepared statement took 7ms
DEBUG slick.jdbc.StatementInvoker.result - /--------------------\
DEBUG slick.jdbc.StatementInvoker.result - | 1 |
DEBUG slick.jdbc.StatementInvoker.result - | concat(table_name) |
DEBUG slick.jdbc.StatementInvoker.result - |--------------------|
DEBUG slick.jdbc.StatementInvoker.result - | Org |
DEBUG slick.jdbc.StatementInvoker.result - | OrgUser |
DEBUG slick.jdbc.StatementInvoker.result - | PermissionList |
DEBUG slick.jdbc.StatementInvoker.result - | PermissionType |
DEBUG slick.jdbc.StatementInvoker.result - | User |
DEBUG slick.jdbc.StatementInvoker.result - \--------------------/
DEBUG slick.jdbc.StatementInvoker.result - 1 more rows read (6 total)
DEBUG slick.basic.BasicBackend.action - #2: success Vector(slick.jdbc.SQLActionBuilder$$anon$1@3e4a6e4b, slick.jdbc.SQLActionBuilder$$anon$1@267dd7e5, slick.jdbc.SQLActionBuilder$$anon$1@6a736f6d, slick.jdbc.SQLActionBuilder$$anon$1@68834f9f, slick.jdbc.SQLActionBuilder$$anon$1@5d64cf2, slick.jdbc.SQLActionBuilder$$anon$1@4d5c7152)
根据詹姆斯的建议,我写了以下内容:
val tablesToDrop : DBIO[Vector[String]] = sql"SELECT concat(table_name) FROM information_schema.tables WHERE table_schema = '#$databaseName';".as[String]
def dropTable(tableNames: Vector[String]) : DBIO[Vector[String]] =
sql"DROP TABLE IF EXISTS #${tableNames.mkString(", ")};".as[String]
val dropTablesDbio : DBIO[Vector[String]] = for {
tables <- tablesToDrop
_ <- sqlu"SET FOREIGN_KEY_CHECKS = 0;"
_ <- dropTable(tables)
_ <- sqlu"SET FOREIGN_KEY_CHECKS = 1;"
} yield tables
只要表列表为非空,它就起作用。空列表大小写会导致sql语法错误。有没有一种优雅的方法来检查空表?
我在想如果我能发送
DBIO.seq(sqlu"DROP TABLE IF EXISTS Table0;",..., sqlu"DROP TABLE IF EXISTS TableN;")
像sql一样,它将更优雅地覆盖空表列表的大小写。
此版本不适用于任何表:
def dropTables = {
val tablesToDrop: DBIO[Vector[String]] = sql"SELECT table_name FROM information_schema.tables WHERE table_schema = '#$databaseName';".as[String]
def dropTables(tableNames: Vector[String]): DBIO[Int] =
sqlu"DROP TABLE IF EXISTS #${tableNames.mkString(", ")};"
def dropTable(name: String): DBIO[Int] = sqlu"DROP TABLE IF EXISTS #$name;"
val dropTablesDbio: DBIO[Vector[String]] = {
tablesToDrop.flatMap(tables => {
if (tables.isEmpty)
DBIO.successful[Vector[String]](Vector.empty)
else {
for {
_ <- sqlu"SET FOREIGN_KEY_CHECKS = 0;"
_ <- dropTables(tables)
_ <- sqlu"SET FOREIGN_KEY_CHECKS = 1;"
} yield tables
}
})
}
val future = dbConfig.db.run(dropTablesDbio.withPinnedSession)
val r = Await.result(future, Duration.Inf)
r.foreach(println(_))
}
答案 0 :(得分:0)
DROP TABLE IF EXISTS
需要如下表的列表:
DROP TABLE IF EXISTS A, B, C
我不认为此查询接受绑定变量(在准备好的语句中设置的变量)。相反,您要做的是将表名用作String文字,而不是绑定变量。
您不需要SetParameter
隐式val。尝试如下替换DELETE查询:
DROP TABLE IF EXISTS #${table.mkString(",")};
Ref:http://slick.lightbend.com/doc/3.2.3/sql.html#splicing-literal-values
还值得注意的是,您应该在删除表之前禁用外键检查,然后在删除它们后重新启用它。请参阅:https://stackoverflow.com/a/4922312/2110188