我建立了一个Oracle数据库(版本9.2,我知道它已经过时,但它是我大学安装的版本,我没有选择),有一个用户列表和他们的直接朋友.我正在处理一组查询以列出用户的“网络”,包括他的朋友的朋友,并计算有问题的用户与其他成员之间的分离程度.
我分别测试了三个查询,并确认它们确实有效.
我现在想要创建一个PL / SQL过程来组合3个查询,以便能够将播放器的ID作为参数提供,但也可以使用一个Execute语句启动三个查询.
但是,我无法运行该程序.我甚至无法转换过程中的第一个查询(请参阅下面的代码).
有人可以解释一下我做错了什么吗?
以下是查询(它们正在运行):
INSERT INTO UserFriendsCopy
SELECT *
FROM UserFriends
WHERE PlayerID < FriendsWith;
INSERT INTO Degrees_Separation
SELECT PlayerID, FriendsWith, LEVEL AS Degree
FROM UserFriendsCopy
START WITH PlayerID = 1
CONNECT BY PRIOR FriendsWith = PlayerID;
SELECT FriendsWith, MIN(Degree)
FROM Degrees_Separation
GROUP BY FriendsWith;
这是我编写的替换第一个查询的过程.它不起作用.为什么?
CREATE OR REPLACE PROCEDURE procDegrees1
AS
DECLARE
CURSOR UserFriendsNoDupl IS SELECT * FROM UserFriends WHERE PlayerID < FriendsWith;
BEGIN
FOR record IN UserFriendsNoDupl
LOOP
EXIT WHEN UserFriendsNoDupl%NOTFOUND;
INSERT INTO UserFriendsCopy VALUES(record.PlayerID, record.FriendsWith);
END LOOP;
END;/
EXECUTE procDegrees1/
[更新]我已重新编写如下程序,以考虑到目前为止收到的意见.不过,它不起作用.
CREATE OR REPLACE PROCEDURE procDegrees1
AS
BEGIN
FOR record IN (SELECT * FROM UserFriends WHERE PlayerID < FriendsWith)
LOOP
INSERT INTO UserFriendsCopy(PlayerID,FriendsWith) VALUES(record.PlayerID, record.FriendsWith);
END LOOP;
END;/
顺便说一下,这里是表定义,以及一些虚拟记录:
DROP TABLE Degrees_Separation;
DROP TABLE UserFriends;
DROP TABLE UserFriendsCopy;
CREATE TABLE UserFriends (
PlayerID INT NOT NULL,
FriendsWith INT NOT NULL,
CONSTRAINT pkUserFriends
PRIMARY KEY (PlayerID, FriendsWith),
CONSTRAINT fkPlayerIDThird
FOREIGN KEY (PlayerID)
REFERENCES Player (PlayerID),
CONSTRAINT fkPlayerIDFourth
FOREIGN KEY (FriendsWith)
REFERENCES Player (PlayerID)
);
CREATE TABLE UserFriendsCopy (
PlayerID INT NOT NULL,
FriendsWith INT NOT NULL,
CONSTRAINT pkUserFriendsBis
PRIMARY KEY (PlayerID, FriendsWith)
);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (1, 2);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (2, 1);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (2, 3);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (3, 2);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (2, 4);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (4, 2);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (1, 4);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (4, 1);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (5, 6);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (6, 5);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (3, 8);
INSERT INTO UserFriends (PlayerID, FriendsWith)
VALUES (8, 3);
CREATE TABLE Degrees_Separation (
PlayerID INT NOT NULL,
FriendsWith INT NOT NULL,
Degree INT NOT NULL,
CONSTRAINT fkPlayerIDSeventh
FOREIGN KEY (PlayerID)
REFERENCES Player (PlayerID),
CONSTRAINT fkPlayerIDEighth
FOREIGN KEY (FriendsWith)
REFERENCES Player (PlayerID)
);
谢谢,LC
最佳答案
SQL*Plus reference says:
SQL*Plus treats PL/SQL subprograms in the same manner as SQL commands, except that a semicolon (;) or a blank line does not terminate and execute a block. Terminate PL/SQL subprograms by entering a period (.) by itself on a new line. You can also terminate and execute a PL/SQL subprogram by entering a slash (/) by itself on a new line.
您将斜杠放在与结尾相同的行上;这是无效的.你需要这样做:
CREATE OR REPLACE PROCEDURE procDegrees1
AS
BEGIN
FOR record IN (SELECT * FROM UserFriends WHERE PlayerID < FriendsWith)
LOOP
INSERT INTO UserFriendsCopy(PlayerID,FriendsWith)
VALUES(record.PlayerID, record.FriendsWith);
END LOOP;
END;
/
当你用execute调用它时,你应该用分号结束,而不是斜杠:
EXECUTE procDegrees1;
这是匿名块的SQL * Plus简写,执行后的内容成为匿名块中的单个语句,因此它被扩展用于实际执行,与执行此操作相同:
BEGIN
procDegrees1;
END;
/
您可以看到,如果语句本身导致错误.但重要的是要注意执行它不是SQL语句,它是一个客户端命令. SQL * Plus和SQL Developer认可它,但其他客户可能不会.
在您评论中提到您使用Squirrel之前,我开始回答这个问题.我不知道Squirrel是否允许执行,但是你得到的错误表明没有.如果没有,那么您将需要使用扩展的匿名块表单,该表单应该可以在任何地方使用.
不支持执行的Google suggests,但您可以执行此操作:
CALL procDegrees1
……但我不知道这是不是真的……