2015-02-11 30 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