查找必须搜索表以获取匹配Oracle数据库的次数

时间:2015-05-01 14:14:59

标签: sql select numbers oracle9i bacon-number

我在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)中工作的演员(援助)的数据。

我想要做的与制定Bacon number

类似

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

我不知道如何计算(仅使用SQL语句)我必须连接给定actor(通过另一个辅助)的actor数量,以找到与517635的连接。

查询的结果可能是给定演员必须连接的所有演员的列表,以获取我的家伙或只是一个号码。

为此,我认为我必须先获得517635所有参与者的所有参与者,并且因为与他直接合作会产生1。这张桌子不是太大,但足够大,可以让它变得不可靠。

例子,让我们说布拉德皮特是我的517635.他与安吉丽娜朱莉一起在史密斯先生和史密斯夫人身上工作,这将使她成为第一名。如果布拉德皮特从未在任何电影中与布鲁斯威利斯合作过(让& #39; s说的是这样的情况)但安吉丽娜朱莉与他在一起然后布鲁斯威利斯'布拉德皮特的数字是2。

在我的查询中,如果给定的数字是安吉丽娜,结果将是: "布拉德皮特1"或者只是" 1" 如果给定的数字是Willis'结果将是: "安吉丽娜朱莉  布拉德皮特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完全陌生,我所能想到的只会导致带有变量的无限循环来计算循环次数。 关于从哪里开始的任何想法,幸运的是,结束了吗?

2 个答案:

答案 0 :(得分: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的{​​{1}}相互连接。
  • fid子句将每组连接的connect by连接到另一组aid
  • aid子句阻止无限递归。
  • nocycle是一个关键字,它为我们提供了递归发生的次数。我们必须得到最小值,因为任何给定的level都可以通过多条路径连接到起始aid
  • 如果此查询执行得非常糟糕,您可能只希望在一定距离内获得结果。执行此操作的最佳方法是将aid添加到and level <= 100子句中(在这种情况下,将结果限制为100或更小的距离)。

正如评论中所指出的,9i不支持connect by。此外,运行此查询时,OP的临时空间不足。这两者实际上是无关的:如果发生循环,Oracle将抛出错误;这意味着在找到循环之前服务器的临时空间不足。我认为没有任何好办法解决这些问题。

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

答案 1 :(得分: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;