2013-08-15 20 views
27

Ich verwende Slick 1, und ich muss in der Lage sein, einen Filter in einer Abfrage anzuwenden, um alle Entitäten zu suchen, die einer Bedingung in einer verwandten Tabelle entsprechen.SELECT DISTINCT in Scala slick

Dieses Beispiel mit der Slick-Dokumentation zeigt, was ich versuche (dies ist ein künstliches Beispiel, das meiner Situation sehr nahe kommt).

Hier möchte ich alle Kaffees, die von Lieferanten an der Westküste zur Verfügung gestellt werden. Ich möchte nur der Kaffee, ich bin nur daran interessiert zu Lieferanten in der Navigation durch das Filter anzuwenden:

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

Dies funktioniert ok, aber es wird Coffees dupliziert, wenn es mehr als eine Übereinstimmung in der Tabelle Lieferanten ist.

Die offensichtliche Problemumgehung ist in normalen SQL, eine SELECT-DISTINCT auszuführen; Aber ich kann hier keinen Weg finden, das zu tun.

Sie könnten theoretisch tun ein:

query.list.distinct 

Nachdem die Ergebnisse bereits zurückgegeben werden; Allerdings habe ich auch die PAGING-Unterstützung implementiert, so dass Sie die Ergebnisse nicht mehr verarbeiten möchten, sobald sie bereits aus der Datenbank zurückkommen. Hier ist die Paging-Unterstützung:

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

So, kurz gesagt, ich brauchen eine Möglichkeit, SELECT angeben DISTINCT in meiner Anfrage, die hinausgeht.

Wer hat irgendwelche Ideen?

Antwort

17

Als Arbeit um Sie versuchen können, groupBy verwenden:

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

Es sollte die gleiche Semantik wie verschieden, aber ich bin mir nicht sicher über die Leistung.

+0

Hey, dieser hat funktioniert! Ich bin mir nicht ganz sicher, warum, ich habe nicht tiefer getaucht, aber ich brauchte eine schnelle Lösung. – noplay

+0

Aus irgendeinem Grund gibt mir das eine "scala.TupleN" statt "XxxRow" Einheit, mit "ClassCastException" geworfen. –

+0

Sieht aus wie dies die Ursache ist: https://github.com/slick/slick/pull/735 –

13

Mit Slick 3.1.0 können Sie distinct und distinctOn Funktionen (Slick 3.1.0 release notes) verwenden. Zum Beispiel:

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, im Moment scheint [ein Bug mit distinctOn] (https://github.com/slick/slick/issues/1712) zu sein. – Nick

2

für verschiedene auf mehreren Säulen coffee.name und 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

Es muss die ** spezifische Reihenfolge ** sein, die Sie beschrieben haben - zB 'map (a => (a.id, a.name)). DisctinctOn (a => (a._1, a._2))' oder man bekommt 'slick key not found: s2' Laufzeitfehler. 'DistinctOn (a => (a.id, a.name))' wird nicht funktionieren –