2015-02-11 73 views
4

我有以下SQL查询,我想但是类似符号不为字符串定义为映射到油滑油滑:与作为参数的列LIKE查询

SELECT * FROM rates 
WHERE '3113212512' LIKE (prefix || '%') and present = true 
ORDER BY prefix DESC 
LIMIT 1; 

其中:

case class Rate(grid: String, prefix: String, present: Boolean) 

class Rates(tag: Tag) extends Table[Rate](tag, "rates") { 
    def grid = column[String]("grid", O.PrimaryKey, O.NotNull) 
    def prefix = column[String]("prefix", O.NotNull) 
    def present = column[Boolean]("present", O.NotNull) 

    // Foreign keys 
    def ratePlan = foreignKey("rate_plan_fk", ratePlanId, RatePlans)(_.grid) 
    def ratePlanId = column[String]("rate_plan_id", O.NotNull) 

    def * = (grid, prefix, present) <>(Rate.tupled, Rate.unapply) 
} 

object Rates extends TableQuery(new Rates(_)) { 
    def findActiveRateByRatePlanAndPartialPrefix(ratePlan: String, prefix: String) = { 
    DB withSession { 
     implicit session: Session => 
     Rates.filter(_.ratePlanId === ratePlan) 
      .filter(_.present === true) 
      .filter(prefix like _.prefix) 
      .sortBy(_.prefix.desc).firstOption 
    } 
    } 
} 

显然,这是合乎逻辑的,这样的事情是行不通的:

.filter(prefix like _.prefix) 

和:

.filter(_.prefix like prefix) 

将呈现不正确的SQL,而我还没有考虑到 '%' 现在(仅在关于前缀子句:

(x2."prefix" like '3113212512') 

相反的:

'3113212512' LIKE (prefix || '%') 

中当然我可以使用静态查询来解决这个问题,但我想知道这是否可能?

为了清楚起见,这里是数据库中的某些前缀

31 
3113 
312532623 
31113212 

和31113212预期结果

+0

您可以添加生成的SQL吗? – 2015-02-11 12:57:42

+0

我已经更新了这个问题 – 2015-02-11 13:07:56

+0

也许我没有得到它,但这两个不同(除了第二个'%'部分)?你是否将某个字符串与列匹配,或者其他方式的结果是相同的,还是我错过了某些内容?或者,也许你的'prefix'列值已经有一个通配符,在这种情况下,这一切都是有道理的。 – 2015-02-11 13:12:17

回答

2

您可以简单地以支持的样式重写您的查询。我想这应该是等价的:

.filter(s => (s.prefix === "") || s.prefix.isEmpty || LiteralColumn(prefix) like s.prefix) 

如果条件更加复杂,你需要一个CASE表达式,见http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html#case

如果你还是想||运营商则可以将其定义是这样的:

/** SQL || for String (currently collides with Column[Boolean] || so other name) */ 
val thisOrThat = SimpleBinaryOperator[String]("||") 

...

.filter(s => LiteralColumn(prefix) like thisOrThat(s.prefix,"%")) 

我没有尝试这个,虽然我看到我们没有对SimpleBinaryOperator测试。如果不起作用,请在github.com/slick/slick上打开一张票。也许我们也应该改变它来返回一个类型化的函数。我为那个https://github.com/slick/slick/issues/1073添加了一张票。

另见http://slick.typesafe.com/doc/2.1.0/userdefined.html#scalar-database-functions

幸运的是SimpleBinaryOperator甚至没有在这里需要。

+0

嗯,字符串仍然没有'喜欢',所以'前缀像s.prefix'或'(s =>前缀喜欢'将仍然无法工作。 – 2015-02-12 07:18:20

+0

您可能必须强制转换并编写LiteralColumn(前缀).like(...)。如果这不起作用,我可能会误认为我们的运算符的适用性。 – cvogt 2015-02-12 14:09:30

+0

我真的需要||运算符,因为在postgres中这意味着串联,所以你提到thisOrThat,这是有效的:.filter(s => LiteralColumn(prefix)like thisOrThat(s.prefix,“%”))yielding和('3113212512'like(x2。“prefix”||'% ')) – 2015-02-12 14:22:14

0

更新2

一个实际上并不需要的CONCAT,因为它可写成如下:

filter(s => LiteralColumn(prefix) like (s.prefix ++ "%")) 

UPDATE:

后cvogt暗示这是不使用内部油滑的API最终结果:

 val concat = SimpleBinaryOperator[String]("||") 

     Rates.filter(_.ratePlanId === ratePlan) 
      .filter(_.present === true) 
      .filter(s => LiteralColumn(prefix) like concat(s.prefix, "%")) 
      .sortBy(_.prefix.desc).firstOption 

这完全得:

and ('3113212512' like (x2."prefix" || '%')) 

备选:

这似乎是可能的。但请注意,以下方法使用Slick的内部API,并且可能由于API更改而不兼容(请参阅cvogt的评论)我使用Slick 2.1.0。

基本上我创建了一个扩展油滑中,我定义一个定制方案来实现所需的结果:

import utils.Helpers._ 

[...] 

    def findActiveRateByRatePlanAndPartialPrefix(ratePlan: String, prefix: String) = { 
    DB withSession { 
     implicit session: Session => 
     Rates.filter(_.ratePlanId === ratePlan) 
      .filter(_.present === true) 
      .filter(_.prefix subPrefixFor prefix) 
      .sortBy(_.prefix.desc).firstOption 
    } 
    } 

而且会使正确的:

package utils 

import scala.language.{higherKinds, implicitConversions} 
import scala.slick.ast.ScalaBaseType._ 
import scala.slick.ast._ 
import scala.slick.lifted.{Column, ExtensionMethods} 

object Helpers { 
    implicit class PrefixExtensionMethods[P1](val c: scala.slick.lifted.Column[P1]) extends AnyVal with ExtensionMethods[String, P1] { 
    def subPrefixFor[P2, R](prefix: Column[P2])(implicit om: o#arg[String, P2]#to[Boolean, R]) = { 
     om.column(Library.Like, prefix.toNode, om.column(new Library.SqlOperator("||"), n, LiteralNode("%")).toNode) 
    } 
    } 
} 

如下这现在可以使用结果:

and ('3113212512' like (x2."prefix" || '%')) 

备注:

  1. 我大概可以有一些更好的命名
  2. 只好链||和使用om.column
  3. 我引入了新的SqlOperator,因为Or运算符呈现或者我需要在Postgres中连接||
+0

这项工作,但需要深入到浮油和使用不太稳定,内部apis。所以如果你能避免它,让我们试着留在光滑的公开API上。 – cvogt 2015-02-11 21:49:45

+0

虽然:) – cvogt 2015-02-11 21:50:43