Scala Slick:如何将类似SQL的语句与SQL IN语句组合在一起

Scala Slick:如何将类似SQL的语句与SQL IN语句组合在一起,scala,slick,sql-like,sql-in,Scala,Slick,Sql Like,Sql In,我基本上希望用更“流畅”的代码替换以下代码: 因此,生成的SQL将是: SELECT u.first_name, u.last_name FROM users u WHERE last_name ~* '%bar|baz%'; 因此,这个dbAction将返回一个action,我可以使用它来查询列表中包含某些名称部分的所有用户 所以 将返回一个操作,查询包含字符串“bar”或“baz”(不区分大小写)的所有姓氏。 我找到了一种查询单个模式的方法 val query = for { user

我基本上希望用更“流畅”的代码替换以下代码:

因此,生成的SQL将是:

SELECT u.first_name, u.last_name
FROM users u
WHERE last_name ~* '%bar|baz%';
因此,这个dbAction将返回一个action,我可以使用它来查询列表中包含某些名称部分的所有用户

所以

将返回一个操作,查询包含字符串“bar”或“baz”(不区分大小写)的所有姓氏。 我找到了一种查询单个模式的方法

val query = for {
  user <- users if user.lastName like "%bar%"
} yield (user.firstName, user.lastName)
由于这是一个不同的问题如何使用正则表达式,我为此创建了一个不同的问题:

只需组合这两个查询条件:

import slick.lifted.Tag
import slick.jdbc.H2Profile.api._
import scala.concurrent.duration._
import scala.concurrent.Await

object Test {
  final case class User(firstName:String, lastName:String, id:Long = 0l)

  class UserTable(tag: Tag) extends Table[User](tag, "user"){
    def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
    def firstName = column[String]("first_name")
    def lastName = column[String]("last_name")
    def * = (firstName, lastName, id).mapTo[User]
  }



  def main(args:Array[String]):Unit = {
    val db = Database.forConfig("h2config")
    val users = TableQuery[UserTable]

    val initialData = Seq(
      User("Alex", "Arendar"),
      User("David", "Arora"),
      User("Dude", "Stoecki"),
      User("Alexander", "the Great")
    )

    Await.result(
      db.run(
        users.schema.create  andThen (users ++= initialData)
      ), 3 seconds
    )

    val query1 = for {
      user <- users if user.firstName like "%Alex%"
    } yield (user.firstName, user.lastName)

    println(query1.result.statements.head)
    println(Await.result(db.run(query1.result), 3 seconds))

    val query2 = for {
      user <- users if (user.firstName like "%Alex%") && user.firstName.inSet(Seq("Alex", "David"))
    } yield (user.firstName, user.lastName)

    println(query2.result.statements.head)
    println(Await.result(db.run(query2.result), 3 seconds))

    db.close()
  }
正如您所看到的,生成的SQL确实包含
like
in
部分


我在这里使用内存H2数据库,但我认为这应该适用于任何RDBMS。

只需结合这两个查询条件:

import slick.lifted.Tag
import slick.jdbc.H2Profile.api._
import scala.concurrent.duration._
import scala.concurrent.Await

object Test {
  final case class User(firstName:String, lastName:String, id:Long = 0l)

  class UserTable(tag: Tag) extends Table[User](tag, "user"){
    def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
    def firstName = column[String]("first_name")
    def lastName = column[String]("last_name")
    def * = (firstName, lastName, id).mapTo[User]
  }



  def main(args:Array[String]):Unit = {
    val db = Database.forConfig("h2config")
    val users = TableQuery[UserTable]

    val initialData = Seq(
      User("Alex", "Arendar"),
      User("David", "Arora"),
      User("Dude", "Stoecki"),
      User("Alexander", "the Great")
    )

    Await.result(
      db.run(
        users.schema.create  andThen (users ++= initialData)
      ), 3 seconds
    )

    val query1 = for {
      user <- users if user.firstName like "%Alex%"
    } yield (user.firstName, user.lastName)

    println(query1.result.statements.head)
    println(Await.result(db.run(query1.result), 3 seconds))

    val query2 = for {
      user <- users if (user.firstName like "%Alex%") && user.firstName.inSet(Seq("Alex", "David"))
    } yield (user.firstName, user.lastName)

    println(query2.result.statements.head)
    println(Await.result(db.run(query2.result), 3 seconds))

    db.close()
  }
正如您所看到的,生成的SQL确实包含
like
in
部分


我在这里使用了内存H2数据库,但我认为这将适用于任何RDBMS。

查看您发布的代码,我认为您不需要将
中的
之类的
进行文字组合。我把这个问题理解为想做一个正则表达式查询。尽管Slick不支持开箱即用的
~*
操作符,但您可以自己添加它。这将为您提供一种使用Slick查询的提升嵌入式样式执行查询的方法

为此,可以使用
SimpleExpression
builder。关于它的文档不多,但起点应该是参考手册的那一页

我们要做的是按照以下思路编写一个方法:

def find(names: Seq[String]): DBIO[Seq[String]] = {
  val pattern = names.mkString("|")
  users.filter(_.lastName regexLike pattern).map(_.lastName).result
}
要获得
regexLike
,我们可以丰富(增强“pimp”)字符串列,以使用
regexLike
方法:

implicit class RegexLikeOps(s: Rep[String]) {
  def regexLike(p: Rep[String]): Rep[Boolean] = {
    val expr = SimpleExpression.binary[String,String,Boolean] { (s, p, qb) =>
      qb.expr(s)
      qb.sqlBuilder += " ~* "
      qb.expr(p)
    }
    expr.apply(s,p)
  }
}
隐式类
部分允许编译器在任何时候都构造
RegexLikeOps
类,只要它有一个
Rep[String]
调用一个
Rep[String]
还没有的方法(即,当要求
regexLike
时)

我们的
regexLike
方法采用另一个
Rep[String]
参数作为模式,然后使用
SimpleExpression
builder安全地构造我们想要使用的SQL

综合起来,我们可以写:

val program = for {
  _ <- users.schema.create
  _ <- users ++= User("foo") :: User("baz") :: User("bar") :: Nil
  result <- find( Seq("baz","bar") )
} yield result

println( Await.result(db.run(program), 2.seconds) )

完整的代码是:

查看您发布的代码,我认为您不需要将
中的
与类似
进行文字组合。我把这个问题理解为想做一个正则表达式查询。尽管Slick不支持开箱即用的
~*
操作符,但您可以自己添加它。这将为您提供一种使用Slick查询的提升嵌入式样式执行查询的方法

为此,可以使用
SimpleExpression
builder。关于它的文档不多,但起点应该是参考手册的那一页

我们要做的是按照以下思路编写一个方法:

def find(names: Seq[String]): DBIO[Seq[String]] = {
  val pattern = names.mkString("|")
  users.filter(_.lastName regexLike pattern).map(_.lastName).result
}
要获得
regexLike
,我们可以丰富(增强“pimp”)字符串列,以使用
regexLike
方法:

implicit class RegexLikeOps(s: Rep[String]) {
  def regexLike(p: Rep[String]): Rep[Boolean] = {
    val expr = SimpleExpression.binary[String,String,Boolean] { (s, p, qb) =>
      qb.expr(s)
      qb.sqlBuilder += " ~* "
      qb.expr(p)
    }
    expr.apply(s,p)
  }
}
隐式类
部分允许编译器在任何时候都构造
RegexLikeOps
类,只要它有一个
Rep[String]
调用一个
Rep[String]
还没有的方法(即,当要求
regexLike
时)

我们的
regexLike
方法采用另一个
Rep[String]
参数作为模式,然后使用
SimpleExpression
builder安全地构造我们想要使用的SQL

综合起来,我们可以写:

val program = for {
  _ <- users.schema.create
  _ <- users ++= User("foo") :: User("baz") :: User("bar") :: Nil
  result <- find( Seq("baz","bar") )
} yield result

println( Await.result(db.run(program), 2.seconds) )

完整代码是:

如果(user.lastName类似“%bar%”)和user.lastName.inSet(Seq(“bar”、“baz”)
不起作用?查看生成的SQL语句会很有趣这不是我想要实现的。我希望获得与上面第一个代码部分中的sql语句相同的结果。如果(user.lastName类似“%bar%”)和user.lastName.inSet(Seq(“bar”,“baz”))不起作用,我将在编辑
中添加插入的sql语句?查看生成的SQL语句会很有趣这不是我想要实现的。我希望获得与上面第一个代码部分中的sql语句相同的结果。我将在一个编辑器中添加插值sql语句。这不是我想要的。我有一个类似于Seq(“%le%”,%av%)的模式列表,并希望对该模式列表进行查询,而不是将类似SQL的语句与SQL-in语句连接起来。您的数据示例的结果将是Vector((亚历克斯,阿伦达),(“大卫”,“阿罗拉”),(亚历山大大帝))。谢谢你,这不是我想要的。我有一个类似于Seq(“%le%”,%av%)的模式列表,并希望对该模式列表进行查询,而不是将类似SQL的语句与SQL-in语句连接起来。您的数据示例的结果将是Vector((亚历克斯,阿伦达),(“大卫”,“阿罗拉”),(亚历山大大帝))。谢谢你,这就解决了我的问题。非常感谢。如果我看对了,你基本上可以创建任何类型的sql操作符,对吗?很酷的功能。@Stoecki是的,这是一个有用的功能。有点相关,如果你还没有看到,还有一个为Postgres添加了其他功能的功能。@RichardDallaway是的,我今天找到了这个存储库,但到目前为止没有深入研究它。但我会的。谢谢你指点。这解决了我的问题。非常感谢。如果我看对了,你基本上可以创建任何类型的sql操作符,对吗?很酷的功能。@Stoecki是的,这是一个有用的功能。有点相关,如果你还没有看到,还有一个为Postgres添加了其他功能的功能。@RichardDallaway是的,我今天找到了这个存储库,但到目前为止没有深入研究它。但我会的。谢谢你指点它。
val program = for {
  _ <- users.schema.create
  _ <- users ++= User("foo") :: User("baz") :: User("bar") :: Nil
  result <- find( Seq("baz","bar") )
} yield result

println( Await.result(db.run(program), 2.seconds) )
select "last_name" from "app_user" where "last_name" ~* 'baz|bar'