5

我在想办法解决 Oracle 对 HAVING EVERY 子句缺乏支持的问题时遇到了麻烦。

我有两个表,Production 和 Movie,具有以下架构:

Production (pid, mid)
Movie(mid, director)

其中“pid”是表示发行商 ID 的整数,“mid”是表示电影 ID 的整数,director 是电影导演的姓名。

我的目标是获取仅出版过由彼得·杰克逊或本·阿弗莱克导演的电影的出版商列表(按 ID)。

为了实现这一点,我编写了以下查询:

SELECT *
    FROM Production P, Movie M
    WHERE P.mid = M.mid;
    GROUP BY P.pid
    HAVING EVERY ( M.director IN ('Ben Affleck', 'Peter Jackson') );

但由于 Oracle 不支持 HAVING EVERY,我得到的只是以下错误:

    HAVING EVERY ( M.director IN ('ben affleck', 'PJ') )
                          *
ERROR at line 5:
ORA-00907: missing right parenthesis

因为导演职位必须适用于出版商制作的每一部电影,所以我不认为可以将条件移至 WHERE 子句。

有没有办法绕过这个障碍?任何被认为是“标准”的东西?另外(也许更重要的是)为什么 Oracle 选择不实施 HAVING EVERY?

4

5 回答 5

5

试试这个:

SELECT P.pid
FROM (select distinct Pi.pid, M.Director
      from Production Pi INNER JOIN 
    Movie M ON Pi.mid = M.mid) P
GROUP BY P.pid
HAVING sum(case when P.Director in ('Ben Affleck', 'Peter Jackson') 
           then 1 else 99 end) = 2

这是一个 sqlfiddle 演示

于 2013-02-21T21:48:28.123 回答
3

在考虑了一段时间之后,我想出了一些可能比 ABCade 想出的更具可读性的东西:

select distinct P.pid
    from Production P
    where P.pid not in (
        -- Get publishers that have produced a movie directed by someone else
        select P1.pid
        from Production P1 INNER JOIN Movie M ON P1.mid = M.mid
        where M.director not in ('Ben Affleck', 'Peter Jackson')
    )

SQLFiddle 演示

不同之处在于,我们不是只寻找具有所需导演的制片人,而是识别与其他导演相关的所有制片人,然后将其省略。

于 2013-02-21T22:58:51.307 回答
2

基于Dan 自己的回答,但我已经删除了相关子查询,因为它在大型数据集上的性能可能会很差:

SELECT DISTINCT P.pid
FROM Production P
LEFT JOIN (
    SELECT P1.pid
    FROM Production P1
    INNER JOIN Movie M ON (P1.mid = M.mid)
    WHERE M.director NOT IN ('Ben Affleck', 'Peter Jackson')
) V ON (P.pid = V.pid)
WHERE v.pid IS NULL;

SQL Fiddle 演示

于 2013-02-21T23:07:31.183 回答
0

为了避免神奇的数字 99

SELECT 
    P.pid
FROM 
(
    SELECT DISTINCT 
        Pi.pid, M.Director
    FROM Production Pi 
    JOIN Movie M ON Pi.mid = M.mid
) P
GROUP BY 
    P.pid
HAVING 
    COUNT(p.Director) = 2 -- The directors should be exactly 2
    AND MIN(CASE WHEN p.Director in ('Ben Affleck', 'Peter Jackson') 
            THEN 1 ELSE 0 END) = 1

其他方法:http ://www.anicehumble.com/2019/04/not-every-rdbms-has-every.html

请注意,not in不能使用双重方法。因为它仍然会报告只有一位与本·阿弗莱克或彼得·杰克逊相匹配的导演的出版商。

with production as
(
   select *
   from (values 
      ('DC', 'Batman', 'Ben Affleck'),
      ('DC', 'Robin', 'Peter Jackson'),
      ('Not DC', 'Not Batman', 'Not Ben Affleck'),
      ('Not DC', 'Not Robin', 'Not Peter Jackson'),         
      ('Marvel', 'Avengers', 'Joe Russo'),
      ('WingNut', 'King Kong', 'Peter Jackson'),
      ('Century Fox', 'Deadpool', 'Ben Affleck'),
      ('Century Fox', 'Fantastic 4', 'Peter Jackson'),
      ('Century Fox', 'X-Men', 'Peter Jackson'),
      ('Millenium Fox', 'Scorpion', 'Ben Affleck'),
      ('Millenium Fox', 'Sub-Zero', 'Peter Jackson'),
      ('Millenium Fox', 'Liu Kang', 'Ed Boon')          
   ) as x(publisher, movie, director)
)
select distinct P.publisher
from production P
where P.publisher not in (
      -- Get publishers that have produced a movie directed by someone else
      select P1.publisher
      from production P1
      where P1.director not in ('Ben Affleck', 'Peter Jackson')
    )
;

错误的输出。WingNut 不应该被包括在内,因为它没有 Ben Affleck 和 Peter Jackson 作为导演。

| publisher   |
| ----------- |
| WingNut     |
| Century Fox |
| DC          |

这是正确的查询,每个都是使用模拟的min(when true then 1 else 0) = 1

with production as
(
   select *
   from (values 
      ('DC', 'Batman', 'Ben Affleck'),
      ('DC', 'Robin', 'Peter Jackson'),
      ('Not DC', 'Not Batman', 'Not Ben Affleck'),
      ('Not DC', 'Not Robin', 'Not Peter Jackson'),         
      ('Marvel', 'Avengers', 'Joe Russo'),
      ('WingNut', 'King Kong', 'Peter Jackson'),
      ('Century Fox', 'Deadpool', 'Ben Affleck'),
      ('Century Fox', 'Fantastic 4', 'Peter Jackson'),
      ('Century Fox', 'X-Men', 'Peter Jackson'),
      ('Millenium Fox', 'Scorpion', 'Ben Affleck'),
      ('Millenium Fox', 'Sub-Zero', 'Peter Jackson'),
      ('Millenium Fox', 'Liu Kang', 'Ed Boon')          
   ) as x(publisher, movie, director)
)
select P.publisher
from (select distinct publisher, director from production) P
group by
    P.publisher
having
     count(p.Director) = 2 -- The directors should be exactly 2

     and min(case when p.Director in ('Ben Affleck', 'Peter Jackson') 
             then 1 else 0 end) = 1
;

正确的输出,应该只显示 DC 和 Century Fox。因为他们是唯一同时雇佣本·阿弗莱克和彼得·杰克逊的出版商。

| publisher   |
| ----------- |
| Century Fox |
| DC          |

现场测试:https ://www.db-fiddle.com/f/aDDw4Pd1DJzs6J5HgbKbdh/4

于 2019-04-11T15:08:55.047 回答
0

使用条件聚合COUNT

SELECT Pi.pid
FROM Production Pi
JOIN Movie M ON Pi.mid = M.mid
GROUP BY Pi.pid
HAVING COUNT(DISTINCT CASE WHEN M.Director IN ('Ben Affleck','Peter Jackson') 
                           THEN M.Director END) = 2;
于 2020-04-04T20:07:36.463 回答