【问题标题】:What would be an optimal SQL query to retrieve the following result set检索以下结果集的最佳 SQL 查询是什么
【发布时间】:2011-11-01 22:11:32
【问题描述】:

首先,这个家庭作业。我已经想到并写了一个解决方案,但我有点恼火的是,我无法成功地对其进行分析,也无法就它是否真的是一个好的解决方案获得第二意见。

假设我有一个简单的电影参与信息表(人、电影、人与电影的关系),如下所示:

create table film
(
    person_name varchar(48) not null,
    film_title varchar(128) not null,
    relation varchar(48) not null
);

-- { 'Mel Gibson', 'Braveheart', 'director' }
-- { 'Mel Gibson', 'Braveheart', 'cast' }
-- { 'Steven Spielberg', 'A.I.' , 'director' }
-- { 'Hilary Swank', 'Million Dollar Baby', 'cast' }
-- etc

数据库和表不是我创建或维护的,我只是从中查询信息。

我需要为在每部他们执导的电影中演员(在镜头前表演)的导演制作一组人名。该条件应该适用于至少导演过一部他们没有出演过的电影的人,或者没有导演过任何东西的人。这些导演是否也与他们没有导演的电影有关系,在这里并不重要。基本上,该查询可以表示为“让我列出在他们执导的每部电影中表演的人的名单”。

我的查询(据我所知产生了正确的结果集),瞧:

(   
    select  person_name 
    from    film 
    where   relation = 'director'
)
except 
(
    select person_name
    from 
    (   
        (
            select  person_name, film_title 
            from    film 
            where   relation = 'director'
        ) 
        except 
        (   
            select  person_name, film_title 
            from    film 
            where   relation = 'cast'
        )
    ) as director_behind_camera_for_film
)

我想知道这个查询是否正确,或者我对此的想法是否完全错误?如果是后者,能否请您提供一个更好的解决方案或解释?

不要太在意我在任何地方都使用字符串(可以使用代理键)这一事实 - 这是一个简化的示例,但它仍然证明了我的挑战。

【问题讨论】:

  • 只是一个小评论:没有必要将个人SELECTs 放在括号中(无论是外部的还是内部的)

标签: sql optimization


【解决方案1】:
SELECT tmp.person_name FROM
(
   SELECT person_name, film_title, COUNT(relationship) as cnt
   FROM film
   WHERE relationship IN ('cast', 'director')
   GROUP BY person_name, film_title
) as tmp
GROUP BY person_name
HAVING SUM(cnt) = COUNT(cnt)*2

SELECT tmp.person_name FROM
(
   SELECT person_name, film_title, COUNT(DISTINCT(relationship)) as cnt
   FROM film
   WHERE relationship IN ('cast', 'director')
   GROUP BY person_name, film_title
) as tmp
GROUP BY person_name
HAVING SUM(cnt) = COUNT(cnt)*2

【讨论】:

  • 我认为您缺少 from 关键字
  • 我困了(即将入睡)。抱歉,如果我犯了语法错误,那只是为了展示我要使用的逻辑
  • @frail,感谢您的努力,这是对我的问题的一个有趣的看法。最重要的是,它似乎有效 :) 明天我会全力以赴。
  • @amn 你知道如果你添加一个关系制片人,这会中断,而某人是导演和制片人,但不是演员
  • @ConradFrix 你是对的,如果你为在电影中扮演多个角色的人添加另一列,它也会中断。所以我放了另一个 sql 来解决这个边缘情况。
【解决方案2】:

“我需要为他们导演的每一部电影中的演员(在镜头前表演)制作一组人名。因此,对于至少导演过一部电影的人来说,条件不成立他们没有演戏,或者没有导演任何东西的人。”

你的短语的后半部分(“或者对于没有导演过任何东西的人”)是不正确的。

如果一个人 X 没有导演任何东西,那么 X 导演的电影集是空集,并且可能已经向您解释(如果不是,那么我现在正在这样做)一个普遍的量化(已在 ALL ...) 中强制转换为空集总是产生“真”。

因此,如果 X 根本没有导演任何东西,那么确实是 X 已经出演了“他导演的所有电影”,因此,X 应该包含在结果集中。 (如果不是这样的需求,需求应该明确说明。)

也就是说,我在Can all SQL queries be represented in Relational Algebra, Domain and Tuple relational calculus 中解释了关系除法的操作细节(这是您获得结果所需要的)。

主题是不同的(经理和员工,而不是导演和电影),但查询的性质是完全相同的:让我找到与所有 Y 有 Z 关系的 X。

编辑

我后来意识到存在“微小”差异:在这个导演、演员和电影的特定示例中,“所有 Y”的集合本身“依赖”于所考虑的特定 X。这是一个额外的复杂性,超出了关系鸿沟的更典型应用范围。解决这个问题可能需要使用关系值属性构建关系,使用 GROUP() 左右,但我还没有弄清楚细节(像 GROUP() 这样的运算符不太可能是你讲座的一部分)。

向任何被引导忽视问题的这一特定方面的人道歉。

【讨论】:

  • 你有很多有效的观点,但我已经编辑了我的问题以更好地指定条件,无论你的理解如何,对于那些导演过零电影的人来说,这应该成立的“全部”的意思。感谢您提供链接(指向相关问题),这是一本非常有用的读物​​。关系划分的问题在于,它要么总是解释不足、解释得不好、根本没有解释,要么在解释时没有教授如何在 SQL 中应用它。
  • 在这种假设下(要求是“至少导演过一部电影并出演过所有电影的人),你的查询是正确的。关于关系划分的问题:这个运算符有相当多的其背后的历史,我知道至少四种不同版本的运算符(可能还有更多),并且所有这些实际上都可以用其他(原始)运算符表示(正如您的示例案例所示)。跨度>
【解决方案3】:

这看起来应该可以工作,而且是更标准的 SQL:

select director.person_name 
from film director 
full outer join film actor 
    on director.person_name = actor.Person_name
    and director.film_title= actor.film_title
where actor.relationship = 'cast'
and director.relationship = 'director'
and actor.person_name is not null
and director.person_name is not null

【讨论】:

  • 如果您添加的人同时在一部电影中导演和表演,然后只在另一部电影中表演,这将不起作用。他们必须在每部电影中都这样做
  • 嗯,在这个Data.SE Query 克林特伊斯特伍德被退回,不应该是由于每个的要求,因为在样本数据中他采取了行动但没有t 导演肮脏的哈利。
  • @Conrad,我认为在这种情况下你有点搞错了——导演可以在他们没有导演的电影中表演(条件成立)。要求是,如果他们导演了一部电影,那么他们必须在其中表演——“对于所有作为 F 的电影,如果 X 导演了 F,那么 X 也必须在 F 中演员”。他们是否也参演或与他们没有导演的电影有其他关系,对这种情况没有影响。
  • @Amn 知道了。由于某种原因,措辞真的让我很困惑
猜你喜欢
  • 2020-05-15
  • 1970-01-01
  • 2020-05-25
  • 2016-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
相关资源
最近更新 更多