1

我基本上想用更“光滑”的东西替换以下代码:

final case class User(firstName: String, lastName: String)

def dbAction(lastNameParts: Seq[String]): SqlStreamingAction[Vector[User], User, Effect]
implicit val getUserResult =
  GetResult((r: PositionedResult) => {
    val resultSet: ResultSet = r.rs
    User(
      resultSet.getString(1),
      resultSet.getString(2)
    )
  })
val pattern = orgIds.mkString("|")
sql"""SELECT u.first_name, u.last_name
      FROM users u
      WHERE last_name ~* $pattern""".as[User]

所以生成的 SQL 将是:

SELECT u.first_name, u.last_name
FROM users u
WHERE last_name ~* '%bar|baz%';

因此,此 dbAction 将返回一个操作,我可以使用该操作来查询列表中包含某些名称部分的所有用户。

所以

dbAction(Seq("bar", "baz"))

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

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

我找到了一种查询列表包含的方法

u <- users if u.lastName.inSet(Seq("bar", "baz"))

但找不到一种方法来结合它

编辑:另一种可能解决这个问题的方法是通过正则表达式。有没有办法实现类似下面的 SQL 语句:

select * from users where last_name ~ '[\w]*bar[\w]*|[\w]*baz[\w]*';

由于这是一个不同的问题,如何使用正则表达式我为此创建了一个不同的问题: Slick:有没有办法用正则表达式创建 WHERE 子句?

4

2 回答 2

4

查看您发布的代码,我认为您不需要将 aIN与 a结合起来LIKE。我读这个问题是想做一个正则表达式查询。虽然 Slick 不支持~*开箱即用的运算符,但您可以自己添加。这将为您提供一种使用 Slick 查询的提升嵌入式样式执行查询的方法。

为此,您可以使用SimpleExpression构建器。关于它的文档不多,但起点是参考手册的Scalar Database Functions页面。

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

def find(names: Seq[String]): DBIO[Seq[String]] = {
  val pattern = names.mkString("|")
  users.filter(_.lastName regexLike pattern).map(_.lastName).result
}

为了得到regexLike我们可以丰富(增强,“皮条客”)一个字符串列来拥有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)
  }
}

implicit class部分是允许编译器在RegexLikeOps任何时候构造类,它Rep[String]调用一个Rep[String]还没有的方法(即,当regexLike被要求时)。

我们的regexLike方法将另一个Rep[String]参数作为模式,然后使用SimpleExpressionbuilder 安全地构造我们想要使用的 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) )

生成的 SQL(在我使用 H2 的测试中)是:

select "last_name" from "app_user" where "last_name" ~* 'baz|bar'

完整代码为:https ://github.com/d6y/so46199828

于 2017-09-14T11:51:40.580 回答
1

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

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()
  }

我的控制台输出是:

select "first_name", "last_name" from "user" where "first_name" like '%Alex%'
Vector((Alex,Arendar), (Alexander,the Great))
select "first_name", "last_name" from "user" where ("first_name" like '%Alex%') and ("first_name" in ('Alex', 'David'))
Vector((Alex,Arendar))

Process finished with exit code 0

如您所见,生成的 SQL 确实包含likein部分。

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

于 2017-09-13T19:59:33.830 回答