【问题标题】:mysql inner join to relate all tuplesmysql内部连接关联所有元组
【发布时间】:2014-12-09 16:55:20
【问题描述】:

我有以下表格:

copy(movie_id,copy_id)
rented(copy_id,outdate,returndate)

如果电影被出租,returndate在数据库中设置为null。

同一部电影会有多个副本。对于单个movie_id,我们可以有多个copy_id。

我需要检索已完全租出的电影,即所有电影的副本都已被租出或以另一种方式放置 - 电影的所有副本都存在于已租借的表中,并且返回日期设置为空。

我尝试过内部联接,但无法将复制表中的所有元组与租用的表相关联。

每个副本都有一个全局唯一的 copy_id。因此,两部不同电影的副本不能具有相同的 copy_id。

如果副本从未被租过,它不会出现在列表中,但这意味着这部电影仍然有库存,因为它从未被租过。这不应该出现。

如果多次租借,同一部电影和副本肯定会出现多次租借。

【问题讨论】:

  • ....GROUP BY movie_ID HAVING SUM(returndate IS NOT NULL)=0
  • ....你怎么知道租了什么电影?如果 2 部不同的电影各有 2 个副本...(电影 A 和 B 的副本 ID 1 和 2)不会复制 ID 2 仍然缺少租借的电影(是 A 电影还是 B 电影?)或者是 copy_Id所有电影的唯一标识符? (例如电影 A 和 B 的 copy_ID 为 1、2、3、4)并且永远不会有重复的 copy_ID?
  • 此外,如果租借中没有记录,则仅表示该副本从未被租借过,因此此类电影不应出现在您的列表中,对吗?换句话说,您想要一个目前没有副本的电影标题列表......同一部电影和副本是否会多次出现在租借中?有趣的问题...
  • 没有足够的信息来回答这个问题。我们需要知道 copy_ID 在所有电影中是否是唯一的,如果不是,那么如果没有租借中的附加字段,特别是 movie_ID,我们就无法完成请求。
  • 我更新了我的问题

标签: mysql sql join data-retrieval


【解决方案1】:

您可以按movie_id分组并计算returndate为null的位置:

SELECT DISTINCT movie_id
FROM copy
JOIN rented
ON copy.copy_id = rented.copy_id
GROUP BY copy.movie_id HAVING COUNT(rented.returndate IS NULL) = 0

【讨论】:

  • 这不会返回从未租借但存在副本的电影。因此不符合“检索已完全出租的电影,即电影的所有副本都已出租”的需要。
  • 如果电影从未被租过但存在副本,那么显然它不会成为已完全租出的电影集合的一部分。
  • 是的,如果不包括从未出租过的副本,那么如何回答“检索已完全出租的电影”的问题?
  • 哦,等等...好吧,我明白你现在在说什么了。是的,这是一个有趣的问题。
【解决方案2】:

这比我想象的要困难一些。我相信这是正确的答案。

“所有电影,其所有副本都存在一个租借的,returndate 为空”

在数学符号中(A=代表所有,E=存在):

{ 米:米| (A c : C | c.movi​​e_id = m.movi​​e_id @( E r : R | r.copy_id = c.copy_id @ r.returndate = null )) @ m.movi​​e_id }

可以改写为:

“所有电影,不存在副本,不存在租借的,returndate 为空”

转换为以下 SQL。

SELECT DISTINCT m.movie_id
FROM Copy m
WHERE NOT EXISTS
  (SELECT 1 FROM Copy c
  WHERE c.movie_id = m.movie_id
  AND NOT EXISTS
    (SELECT 1 FROM Rented r
    WHERE r.copy_id = c.copy_id
    AND returndate IS NULL)

【讨论】:

  • 这不会返回从未租借但存在副本的电影。因此不符合“检索已完全出租的电影,即电影的所有副本都已出租”的需要。
  • 电影 A 有副本 1 和 2。租用的表只有副本 2 的记录,因为副本 1 从未被租用。如果副本 1 从未被租用,它将被您的内部联接排除在外。那么,如果您加入的性质排除了一些从未租过的电影,因此不能完全出租,您怎么能说所有商店的副本都是出租的。我将问题解读为“给我一份我们拥有的电影清单,但目前没有库存”显然,如果它从未被租过,它仍然有库存。
  • 是的,你是对的,它比我想象的要复杂一些。请检查我的编辑,看看现在是否正确。
  • 如果我们假设 copy_ID 在所有电影中都是唯一的,则此方法有效。如果电影 A 有两个副本,副本 ID 1 和 2,而电影 B 有两个副本,也有 Copy_Id 1 和_2...,那么这也行不通。但在 OP 更好地定义之前我们不知道。
  • 确实没有理由认为情况并非如此,即使没有明确提及。
【解决方案3】:

您可以使用left join 和带有having 子句的聚合来做您想做的事情。然后,计算没有返回日期的记录数,并将其与副本数进行比较:

SELECT c.movie_id
FROM copy c LEFT JOIN
     rented r
     ON c.copy_id = r.copy_id
GROUP BY c.movie_id
HAVING SUM(r.returndate IS NULL) = COUNT(DISTINCT c.copy_id)

注意使用SUM() 进行比较。这会计算值为“true”的行数。

上述查询假设一个副本一次不能多次租用。一个合理的假设,但总是值得检查。另一个 having 子句考虑了这一点:

HAVING count(distinct case when r.returndate is null then c.copy_id end) = count(distinct c.copy_id)

【讨论】:

  • +1 我一直很喜欢你的回答;我学到了更多创造性的做事方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 2016-04-13
  • 1970-01-01
相关资源
最近更新 更多