2013-08-15 18 views
27

Sto usando Slick 1 e devo essere in grado di applicare un filtro in una query per cercare tutte le entità che corrispondono a una condizione in una tabella correlata.SELECT DISTINCT in Scala slick

Questo esempio che utilizza la documentazione di Slick mostra ciò che sto cercando di fare (questo è un esempio forzato che è vicino alla mia situazione).

Qui, voglio tutti i caffè forniti dai fornitori sulla costa occidentale. Voglio che il caffè unico, io sono interessato solo a navigazione verso Fornitori per applicare il filtro:

val westCoast = Seq("CA", "OR", "WA") 
val implicitInnerJoin = for { 
    c <- Coffees 
    s <- Suppliers if c.supID === s.id && s.state inSet westCoast 
} yield c 

Questo funziona bene, ma duplicherà Caffè se non v'è più di una corrispondenza nella tabella fornitori.

L'ovvia soluzione è in SQL normale per eseguire un SELECT DISTINCT; tuttavia, non riesco a trovare un modo per farlo qui.

Si potrebbe in teoria fare:

query.list.distinct 

Dopo i risultati sono già restituiti; tuttavia, ho anche implementato il supporto PAGING, quindi non vorrai elaborare i risultati una volta che sono già tornati dal database. Qui è il supporto di paging:

query.drop(offset).take(limit).list 

Quindi, in poche parole, ho bisogno di un modo per specificare SELECT DISTINCT nella mia interrogazione che si spegne.

Qualcuno ha qualche idea?

risposta

17

Per ovviare si può provare a utilizzare groupBy:

query.groupBy(x=>x).map(_._1) 

esso dovrebbe avere la stessa semantica come distinti, ma io non sono sicuro di prestazioni.

+0

Hey, questo ha funzionato! Non sono esattamente sicuro del perché, non ho fatto più di un'immersione profonda, ma avevo bisogno di una soluzione rapida. – noplay

+0

Per qualche motivo, questo mi dà un 'scala.TupleN' invece di un'entità' XxxRow', con 'ClassCastException' generata. –

+0

Sembra che questa sia la causa: https://github.com/slick/slick/pull/735 –

13

Con slick 3.1.0 è possibile utilizzare le funzioni distinct e distinctOn (Slick 3.1.0 release notes). Per esempio:

val westCoast = Seq("CA", "OR", "WA") 
val implicitInnerJoin = for { 
    c <- Coffees 
    s <- Suppliers if c.supID === s.id && s.state inSet westCoast 
} yield c 

db.run(implicitInnerJoin.distinctOn(_.name).result) 
+1

FWIW, sembra esserci [un bug con distinctOn] (https://github.com/slick/slick/issues/1712) al momento. – Nick

2

Per distinta su più colonne coffee.name e coffee.price:

val westCoast = Seq("CA", "OR", "WA") 
val implicitInnerJoin = for { 
    c <- Coffees 
    s <- Suppliers if c.supID === s.id && s.state inSet westCoast 
} yield c 

db.run(implicitInnerJoin.map(f => (f.name, f.price, f.state)).distinctOn(p => (p._1, p._2)).result) 
+0

Deve essere il ** ordine specifico ** che hai descritto, cioè 'map (a => (a.id, a.name)). DisctinctOn (a => (a._1, a._2))' oppure si ottiene la chiave slick non trovata: eccezione di runtime s2'. Fare 'distinctOn (a => (a.id, a.name))' non funzionerà –