2

[PSQLException:错误:重复键值违反唯一约束“dictionary_word_idx”详细信息:键(单词)=(odirane)已经存在。]

我有防止任何重复的唯一索引。我想知道如何插入包含数千个元素但只有新元素的数组?我正在使用 Slick 1.0.1 和 Postgresql 9.1

编辑: 我正在尝试以下操作:

    def run = {
      val source = scala.io.Source.fromFile("/home/user/dev/txt/test1.txt")
      val lines = source.mkString
      source.close()

      val words = lines.split("[^\\p{Ll}]").distinct

      database withTransaction {

        val q = for {
            w <- words.toList
            row <- Dictionary if row.word != w  
        } yield w


        Dictionary.autoInc.insertAll(q: _*)
      }


      words.length
    }

但 t dosent 编译:

 polymorphic expression cannot be instantiated to expected type; 
 [error]  found   : [G, T]scala.slick.lifted.Query[G,T] 
 [error]  required: scala.collection.GenTraversableOnce[?] [error]          
  row <- Dictionary if row.word != w

编辑2:

case class Word(id: Option[Long], word:String)

object Dictionary extends Table[Word]("dictionary") {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def word = column[String]("word")

  def * = id.? ~ word <> (Word, Word.unapply _)
  def dictionary_word_idx = index("dictionary_word_idx", word, unique = true)
  def autoInc = word returning id
}
4

2 回答 2

2

另一种选择是编写原始 SQL。Postgres 没有默认方式on duplicate ignore,但您可以通过几种不同的方式模拟它,此处显示https://dba.stackexchange.com/questions/30499/optimal-way-to-ignore-duplicate-inserts

结合http://slick.typesafe.com/doc/1.0.0-RC2/sql.html

编辑:

这是一个例子

def insert(c: String) =
    (Q.u + """INSERT INTO dictionary
        (word)
    SELECT""" +?  c + 
    """WHERE
        NOT EXISTS (
            SELECT word FROM dictionary WHERE word = """ +? c + ")"
    ).execute

val words = lines.split("[^\\p{Ll}]")

words.foreach(insert)

这就是你所说的“一次”吗?我认为这将是做到这一点而不发疯的最高效的方式。

如果它对您来说太慢,还有另一个建议是创建一个没有唯一约束的临时表,将当前表复制到临时表中,将新单词插入临时表中,然后从该表中选择 distinct。此处显示:https ://stackoverflow.com/a/4070385/375874

但我认为这太过分了。除非你有一些疯狂的要求什么的。

于 2013-08-07T23:56:38.783 回答
1

从概念上讲:

def insertAll[T](items: Seq[T]): Seq[Either[(T, Exception), (T, Int)]] = items.map { i =>
  try {
    // Perform an insert supposing returns and int representing the PK on the table
    val pk = …
    Right(i, pk)
  } catch {
    case e: Exception => Left(i, e)
  }
}

您执行每个插入操作,然后根据结果返回一个 Left 或 Right 对象,该对象跟踪最终结果并为您提供详细的上下文来解释操作。

编辑

假设您的 DAO 对象如下所示:

object Dictionary extends Table[Word]("dictionary") {
   // ...
}

你的对象模型在哪里Word,而且你已经提供了具体细节(我可以从你粘贴的代码中推断出)它应该是(wordsa在哪里Seq[Word]):

words.map { w => 
  try {
    Right(w, Dictionary.autoInc.insert(w))
  } catch {
    case e: Exception => Left(w, e)
  }
}

你得到的是一个序列,Either它封装了进一步处理的结果。

注意事项 我提供的解决方案尝试乐观地对 DB 执行操作,而不需要根据 DB 的状态预先过滤列表。一般来说,预过滤在大量多用户应用程序中是有问题的,前提是您不能假设在您执行过滤后没有人在您的预过滤列表中添加单词。更简单地说:唯一性约束是 DBMS 提供的一个强大的特性,它比重新发明更好地利用。您在上面编辑的解决方案是没有解决方案的,因为您仍然需要面对可能的 PK 违规异常。

于 2013-08-06T10:57:41.570 回答