光滑查询=>重复的结果

时间:2014-07-11 02:52:45

标签: sql scala playframework slick play-slick

我得到了那些模型(简化):

User(id: Int, name: String)
Restaurant(id: Int, ownerId: Int, name: String)
Employee(userId: Int, restaurantId: Int)

当我使用此查询时:

for {
    r <- Restaurants
    e <- Employees
    if r.ownerId === userId || (e.userId === userId && e.restaurantId === r.id)
  } yield r

转换为:

select x2."id", x2."owner_id", x2."name" from "restaurants" x2, "employees" x3 where (x2."owner_id" = 2) or ((x3."user_id" = 2) and (x3."restaurant_id" = x2."id"))

到目前为止没有问题。但是当我插入这些数据时:

User(1, "Foo")
User(2, "Fuu")
Restaurant(1, 2, "Fuu")
Restaurant(2, 1, "Foo")
Restaurant(3, 1, "Bar")
Employee(2, 2)
Employee(2, 3)

然后尝试查询,我得到了这个结果:

List(Restaurant(1, 2, "Fuu"), Restaurant(1, 2, "Fuu"), Restaurant(2, 1, "Foo"), Restaurant(3, 1, "Bar))

我不明白为什么Restaurant(1, 2, "Fuu")出现2次。

(我正在使用org.h2.Driver和网址jdbc:h2:mem:play

我错过了什么吗?

1 个答案:

答案 0 :(得分:1)

为什么要回到4行

交叉连接很难;您对SQL查询的要求是:

-- A Cartesian product of all of the rows in restaurants and employees
Employee.user_id | Employee.restaurant_id | Restaurant.name | Restaurant.owner_id
               2 |                      2 | Fuu             |                   2 
               2 |                      3 | Fuu             |                   2
               2 |                      2 | Foo             |                   1
               2 |                      3 | Foo             |                   1
               2 |                      2 | Bar             |                   1
               2 |                      3 | Bar             |                   1

-- Filtering out those where the owner != 2
Employee.user_id | Employee.restaurant_id | Restaurant.name | Restaurant.owner_id
               2 |                      2 | Fuu             |                   2 
               2 |                      3 | Fuu             |                   2

-- And combining that set with the set of those where the employee's user_id = 2
-- and the restaurant's ID is equal to the employee's restaurant ID
Employee.user_id | Employee.restaurant_id | Restaurant.name | Restaurant.owner_id
               2 |                      2 | Foo             |                   1
               2 |                      2 | Bar             |                   1

如何解决

改为使其显式为左连接:

for {
    (r, e) <- Restaurants leftJoin Employees on (_.id = _.restaurantId)
    if r.ownerId === userId || e.userId === userId
} yield r

或者,使用exists使其更清晰:

for {
  r <- Restaurants
  if r.ownerId === userId ||
     Employees.filter(e => e.userId === userId && e.restaurantId === r.id).exists
} yield r