2015-07-01 11 views
5

Jest podobne pytanie, ale w rzeczywistości nie odpowiada na pytanie.Czy można używać klauzuli IN w zwykłym sql Slick dla liczb całkowitych?

Is it possible to use IN clause in plain sql Slick?

Należy pamiętać, że to jest rzeczywiście częścią większego i bardziej złożonego zapytania, więc trzeba używać zamiast zwykłego SQL zręczny uniósł osadzanie. Coś jak poniżej będą dobre: ​​

val ids = List(2,4,9) 
sql"SELECT * FROM coffee WHERE id IN ($ids)" 

Odpowiedz

11

sql prefiks odblokowuje StringContext gdzie można ustawić parametry SQL. Nie ma parametru SQL dla listy, więc możesz łatwo zakończyć otwarcie się na SQL injection tutaj, jeśli nie jesteś ostrożny. Jest kilka dobrych (i trochę niebezpiecznych) sugestii dotyczących radzenia sobie z tym problemem z SQLServer na this question. Masz kilka opcji:

Najprościej jest prawdopodobnie użyć operatora #$ wraz z mkString interpolować dynamicznego SQL:

val sql = sql"""SELECT * FROM coffee WHERE id IN (#${ids.mkString(",")})""" 

nie poprawnie używać parametrów, a zatem może być otwarty do SQL- wstrzyknięcie i inne problemy.

Inną opcją jest użycie regularny ciąg interpolacji i mkString zbudować oświadczenie:

val query = s"""SELECT * FROM coffee WHERE id IN (${ids.mkString(",")})""" 
StaticQuery.queryNA[Coffee](query) 

To jest zasadniczo takie samo podejście, jak przy użyciu #$, ale może być bardziej elastyczny w przypadku ogólnym.

Jeśli luka SQL-injection jest poważnym problemem (np. Jeśli elementy ids są dostarczane przez użytkownika), można zbudować zapytanie z parametrem dla każdego elementu z ids. Następnie trzeba zapewnić wystąpienie zwyczaj SetParameter tak śliskie, że może obrócić List do parametrów:

implicit val setStringListParameter = new SetParameter[List[String]]{ 
    def apply(v1: List[String], v2: PositionedParameters): Unit = { 
     v1.foreach(v2.setString) 
    } 
} 

val idsInClause = List.fill(ids.length)("?").mkString("(", ",", ")") 
val query = s"""SELECT * FROM coffee WHERE id IN ($idsInClause)""" 
Q.query[List[String], String](query).apply(ids).list(s) 

Ponieważ Twój idsInts, to chyba mniejszy problem, ale jeśli wolisz tej metody, po prostu trzeba zmienić setStringListParameter używać Int zamiast String:

+3

Jeśli 'ids' ma typ' List [Int] 'Nie widzę jak wtrysk sql jest możliwy, nawet jeśli są dostarczane przez użytkownika. – Daenyth

+1

@Daenyth Jest to zdecydowanie mniejszy problem (chociaż czasami całkowite wstrzyknięcie SQL może być problemem, ponieważ powoduje podzielenie przez zero lub inne wyjątki, a następnie wykorzystanie stanu błędu - Google "liczby całkowite wtrysku sql"). Ale uważam, że najlepiej jest używać parametrów, aby uniknąć problemów na drodze (np. Co jeśli inny programista zmienił typ na "Ciąg" w dół, aby uwzględnić nowe typy identyfikatorów, które zawierają niektóre znaki). Naprawdę właśnie zakryłem sprawę, gdy jest tu "String". –

+0

Dzięki za odpowiedź Ben! Bardzo pouczające o rozwiązaniach z możliwymi słabymi punktami. Zgadzam się jednak z @Denyth, że nie można sql wstrzykiwać z jawnym typem całkowitym. –

3
val ids = List(610113193610210035L, 220702198208189710L) 

    implicit object SetListLong extends SetParameter[List[Long]] { 
    def apply(vList: List[Long], pp: PositionedParameters) { 
     vList.foreach(pp.setLong) 
    } 
    } 

    val select = sql""" 
     select idnum from idnum_0 
     where idnum in ($ids#${",?" * (ids.size - 1)}) 
    """.as[Long] 

@Ben Reich ma rację. to jest kolejny przykładowy kod, test na śliskim 3.1.0.

($ids#${",?" * (ids.size - 1)})

1

Chociaż nie jest to uniwersalne rozwiązanie i nie może być to, co autor chciał, wciąż chcę zwrócić na to uwagę, kto patrzy na to pytanie.

Niektóre backendy DB obsługują typy tablic, a istnieją rozszerzenia dla Slick, które umożliwiają ustawienie tych typów tablic w interpolacjach.

Na przykład, PostgreSQL posiada składnię where column = any(array) iz slick-pg można użyć tej składni tak:

def query(ids: Seq[Long]) = db.run(sql"select * from table where ids = any($ids)".as[Long]) 

To przynosi znacznie czystszy składni, które jest przyjazne dla pamięci podręcznej oświadczenie kompilatora, a także bezpieczne od Wstrzyknięcia SQL i ogólne niebezpieczeństwo utworzenia nieprawidłowo utworzonego kodu SQL przy użyciu składni interpolacji #$var.

Powiązane problemy