Scala Doobie。创建并插入临时表

问题描述 投票:0回答:2

我对 Scala 比较陌生,对 Doobie 也比较陌生。我正在连接到 SQL Server 2014,需要创建一个临时表,然后插入到该临时表中。在 SQL Server 中,当您创建临时表并断开连接时,临时表会自动删除。

在以下代码片段中,我收到此异常:

Exception in thread "main" com.microsoft.sqlserver.jdbc.SQLServerException:  Invalid object name '#temp'

片段:

  val create: doobie.ConnectionIO[Int] = sql"CREATE TABLE #temp (tmp CHAR(20))".update.run

  val insert: doobie.ConnectionIO[Int] = sql"INSERT INTO #temp values ('abc'), ('def')".update.run

  val query: doobie.ConnectionIO[List[String]] = sql"select * from #temp  ".query[String].to[List]

  def wrapper(): ConnectionIO[List[String]] = {
    for {
      c <- create
      i <- insert
      q <- query
    } yield q
  }

wrapper().transact(xa).debug.as(ExitCode.Success)

我相信这告诉我 Doobie 正在删除 create 和 insert 语句之间的连接?

预期/期望的行为是它将返回

List("abc","def")

预先感谢您的帮助!

更新:

这是我所知道的实际上有效的一个小例子:

  val create = sql"CREATE TABLE #temp (tmp CHAR(20))"

  val insert: doobie.ConnectionIO[Int] = sql"INSERT INTO #temp values ('abc'), ('def')"


(create ++ insert).update.run.transact(xa).debug.as(ExitCode.Success)

(请注意,它仅适用于创建和插入部分,不适用于查询部分)

scala scala-cats doobie
2个回答
0
投票

用头撞笔记本电脑一周后……我终于想通了。 Doobie 在执行

.query
:

时实际上会执行“更新”命令
  val create: Fragment = sql"CREATE TABLE #temp (tmp CHAR(20))"

  val insert: Fragment = sql"INSERT INTO #temp values ('abc'), ('def')"

  val query: Fragment = sql"select * from #temp  "

  (create ++ insert ++ query).query[String].to[List].transact(xa).debug.as(ExitCode.Success)

输出:

List(abc             ,def            )

0
投票

我也因此而用头撞我的笔记本电脑。

Doobie 似乎对下面的会话做了一些奇怪的事情。临时表在每个会话中共享。理论上,他们应该有相同的会话,因此他们应该共享临时表,但不知怎的,他们在 Doobie 中却没有。

我有一个部分的、hacky 解决方案:

如果您使用global临时表(双

##
而不是单个
#
),它会起作用。

但是,我不确定您是否可以在您的用例中使用全局临时表。它们是每个连接共享的。

您可以确保全局表的表名称是随机的,以避免出现任何问题:

val tableId = "e0c0544d"
Fragment.const(s"CREATE TABLE ##temp_${tableId} (tmp CHAR(20))").update.run.void

但是它并没有解决最初的问题,即 Doobie 对会话做了一些奇怪的事情,因此本地临时表无法正常工作。我也不确定您是否不需要显式删除此表以确保安全,因此您不妨创建一个普通表...

您的解决方案是将 3 个查询粘合到一个查询中 - 不幸的是,它并不适用于所有情况。更多时候,我们希望在一个

sql"..."
中创建一个临时表,从另一个
sql"..."
填充它,并在另一个
sql"..."
中执行某些操作,并使用单个
ConnectionIO
作为一个
.transact
一起执行/处理。

编辑:也许这是一个设计选择。您可以在同一查询中使用本地临时表,在一个查询中使用全局临时表

.transact

© www.soinside.com 2019 - 2024. All rights reserved.