Question

The title is self-explanatory. Using 2.0.0-M3, I'd like to avoid unnecessary verbosity is the form of explicitly naming the columns to be joined on, since they are appropriately named, and since NATURAL JOIN is part of the SQL standard. Not to mention, Wikipedia itself even says that "The natural join is arguably one of the most important operators since it is the relational counterpart of logical AND."

I think the foregoing ought to be clear enough, but just if not, read on. Suppose I want to know the supplier-name and part-number of each part. Assuming appropriate case classes not shown:

class Suppliers(tag: Tag) extends Table[Supplier](tag, "suppliers") {
  def snum  = column[String]("snum")
  def sname = column[String]("sname")
  def * = (snum, sname) <> (Supplier.tupled, Supplier.unapply _)
}

class Shipments(tag: Tag) extends Table[Shipment](tag, "shipments") {
  def snum  = column[String]("snum")
  def pnum = column[String]("pnum")
  def * = (snum, pnum) <> (Shipment.tupled, Shipment.unapply _)
}

val suppliers = TableQuery[Suppliers]
val shipments = TableQuery[Shipments]

Given that both tables have the snum column I want to join on, seems as if

( suppliers join shipments ).run

ought to return a Vector with my desired data, but I get a failed attempt at an INNER JOIN, failing (at run-time) since it's missing any join condition.

I know I can do

suppliers.flatMap( s => shipments filter (sp => sp.snum === s.snum) map (sp => (s.sname, sp.pnum)) )

but, even without the names of all the columns I omitted for clarity of this question, it's still quite a lot more typing (and proofreading) than simply

suppliers join shipments

or, for that matter

SELECT * FROM suppliers NATURAL JOIN shipments;

If the Scala code is messier than the SQL code, then I really start questioning things. Is there no way simply to do a natural join in Slick?

Was it helpful?

Solution

Currently not supported by Slick. Please submit a ticket or pull request.

To improve readability of query code, you can put your join conditions into re-usable values. Or you can put the whole join in a function or method extension of Query[Suppliers,Supplier].

Alternatively you could look at the AutoJoin pattern (which basically makes your join conditions implicit) described here http://slick.typesafe.com/docs/#20130612_slick_vs_orm_scaladays_2013 and implemented here https://github.com/cvogt/play-slick/blob/scaladays2013/samples/computer-database/app/util/autojoin.scala

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top