3

我在 oracle9i 的数据库中有这张表:

CREATE TABLE involved_in
(
    rid number,
    aid number NOT NULL,
    fid number NOT NULL,
    role varchar(80),
    note varchar(80), 
    job varchar(35),
    PRIMARY KEY(rid),
    FOREIGN KEY(fid) REFERENCES production(pr_id),
    FOREIGN KEY(aid) REFERENCES person(pid)
);

其中包含有关在电影 (fid) 中工作的演员 (aid) 的数据。

我想做的类似于计算 培根数

除了我的凯文培根以拥有 517635 的援助而闻名。

我不知道如何计算(仅使用 SQL 语句)我必须连接给定参与者(通过其他帮助)以找到与 517635 的连接的参与者数量。

查询的结果可能是给定演员必须连接到我的人的所有演员的列表,或者只是一个数字。

为此,我认为我必须首先获得与 517635 合作过的所有演员,而那些直接与他合作过的演员会得到 1。这张桌子不是太大,但足够大,可以让它变得不可行。

例如,假设布拉德皮特是我的 517635。他与安吉丽娜朱莉在《史密斯夫妇》中合作,这将使她成为第一名。如果布拉德皮特从未与布鲁斯威利斯合作过任何电影(假设是这样),但安吉丽娜朱莉与他合二为一,那么布鲁斯威利斯相对于布拉德皮特的人数将是 2。

在我的查询中,如果给定的数字是安吉丽娜的,结果将是:“布拉德皮特 1”或只是“1” 如果给定的数字是威利斯,结果将是:“安吉丽娜朱莉布拉德皮特 2”或“2”在表中:

INSERT INTO involved_in(rid, aid, fid, role, note, job) VALUES(1, 33,                  1584953, 'Himself', 'NULL', 'actor');
INSERT INTO involved_in(rid, aid, fid, role, note, job) VALUES(2, 1135, 1999660, 'Himself', 'NULL', 'actor');
INSERT INTO involved_in(rid, aid, fid, role, note, job) VALUES(3, 1135, 2465724, 'Himself', 'NULL', 'actor');
INSERT INTO involved_in(rid, aid, fid, role, note, job) VALUES(4, 6003, 2387806, 'Himself', '(archive footage)', 'actor');
INSERT INTO involved_in(rid, aid, fid, role, note, job) VALUES(5, 13011, 1935123, 'Himself', 'NULL', 'actor');

我什么都没有,我对 SQL 完全陌生,我能想到的所有东西都会导致无限循环,其中有一个变量来计算循环数。关于从哪里开始以及幸运地结束的任何想法?

4

2 回答 2

2

如果没有样本数据,这很难验证,但以下答案至少在语法上是正确的。

你在这里想要的显然是一个递归查询。在 Oracle 中有一些方法可以做到这一点:使用公用表表达式 (CTE)(即with子句);或使用connect by从句。CTE 是 SQL 标准并且connect by是专有的,但我觉得connect by不太容易混淆,所以我将使用它(9i 也不支持递归 CTE)。

SELECT   aid, MIN (lvl) AS distance
FROM     (SELECT     ii2.aid, LEVEL AS lvl
          FROM       involved_in ii1
                     JOIN involved_in ii2
                        ON ii1.fid = ii2.fid AND ii1.aid <> ii2.aid
          START WITH ii1.aid = 517635
          CONNECT BY NOCYCLE ii1.aid = PRIOR ii2.aid)
GROUP BY aid
  • 连接将所有aid共享 a的人连接起来fid
  • connect by子句将每组连接aid到另一组aid.
  • nocycle子句防止无限递归。
  • level是关键字,它为我们提供了递归发生的次数。我们必须得到最小值,因为任何给定的都可以通过多条路径aid连接到起点。aid
  • 如果此查询执行得非常糟糕,您可能只想获得一定距离内的结果。最好的方法是添加and level <= 100connect by子句中(在这种情况下,将结果限制在 100 或更小的距离内)。

正如评论中指出的那样,9i 不支持nocycle. 此外,运行此查询时,OP 的临时空间不足。这两者其实是无关的:如果出现循环,Oracle会抛出错误;这意味着服务器在找到循环之前用完了临时空间。我没有看到任何解决这些问题的好方法。

可以指定一个终点(在某种程度上)。您可以将AND ii1.aid <> 2where 2is theaid端点添加到on子句中。这将导致查询在遇到该值时停止导航分支。然而,这可能对上述问题没有帮助,因为它只会使找到提供值的那些分支短路。它仍然必须评估所有其他分支,以防价值在它们的某个地方。

于 2015-05-01T14:35:05.503 回答
1

最好的方法是使用分层查询。

Oracle(甚至在 9i 版本中)有 CONNECT BY 子句。http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm

结合 START WITH 和 LEVEL,这变得非常容易。

例子:

SELECT last_name, employee_id, manager_id, LEVEL
FROM employees
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY last_name;
于 2015-05-01T14:34:46.863 回答