我在 SQL Developer 中运行 SQL 脚本时遇到问题(问题不是 SQL Developer spe=cific):
它的结构是这样的:
CURSOR MY_CURSOR IS (SELECT * FROM ... JOIN ... WHERE ...);
BEGIN
FOR I IN MY_CURSOR
LOOP
...
END LOOP;
...
END;
即我首先使用一些 SQL select 为自己定义一个游标,然后我想迭代它。
选择部分工作正常(即它使用多个连接并生成一个有效的表),但是一旦我定义了
FOR I IN MY_CURSOR LOOP .... END LOOP;
,我就会收到编译错误:
ORA-06550: line 57, column 5:
PLS-00402: alias required in SELECT list of cursor to avoid duplicate column names
ORA-06550: line 57, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
错误位置(行和列)与往常一样偏离了(不知道为什么 Oracle DB 无法正确计算这些...)并且错误消息通常相当简洁:
如何有效地调试这一点?能否以某种方式让 Oracle DB 发出更多详细信息,尤其是此处。明显不明确的违规列标识符?或者显示光标,以便人们可以看到导致这些冲突的列名称的语句?
我的猜测是,这个问题是由于杂项连接(我的实际语句中有几个)导致某些列名称重复。在结果列表中,我看到这些列名称带有附加的“_1”。有没有办法省略或忽略这些(因为我对这些并不真正感兴趣)来防止此错误?或者我是否真的必须拼写出
select
中的每个列名称(而不是仅仅说明select *
)?
如果 SQL 语句被允许的客户端获取,则其顶级块中可以有重复的列名。当在 PL/SQL 中调用时,PL/SQL 引擎是 SQL 语句的“客户端”,并且它“不允许”允许重复的列名。这就是为什么它可以独立工作,但不能在 PL/SQL 块内工作。 此外,错误堆栈通常会指向遇到解析错误的 SQL 语句的行号,
如果SQL 是独立的。一旦将其嵌入到 PL/SQL 中,您将仅获得指向第一行(SQL 开始的位置)的指针。调试,将其复制粘贴到独立语句中,用虚拟值替换任何 PL/SQL 变量,然后尝试重现错误。然后您应该得到 SQL 中出现问题的行号。 要在 PL/SQL 之外重现重复列错误,只需将 SQL 包装在
select * from ()
:
SELECT * FROM (
SELECT * FROM ... JOIN ... WHERE ...
)
这将引发重复列错误,因为外部查询块要求
*
,这会在内部块中找到多个同名列时出现阻塞。但是,错误号将指向发现解析错误的位置,这将是
first行上的
*
,not 列重复的位置,因为它位于 it 所在的内部块中这实际上是一个问题,直到某些东西(例如外部查询块)需要引用列。所以 Oracle 是准确的:错误不是发生在重复项所在的位置,也不是根本问题所在,而是发生在它无法处理重复项的其他地方。
但是,您可以使用一个技巧来查找重复项。尝试使用 SQL 创建一个 view:
CREATE VIEW test AS SELECT col1,col2,col2,col3 FROM ... JOIN ... WHERE ...
它会抛出重复列错误,但它应该为您提供指向重复项的正确行号和列号。
例如这个Oracle 一次仅处理一个命令(这有助于防止某些 SQL 注入漏洞 -
)。如果您有一个脚本,那么您正在使用的客户端应用程序将解析该脚本并将其拆分为单独的语句,如果存在错误,则行号将引用该命令开头的行(而不是从该命令开头的行)脚本,因为数据库永远不会看到整个脚本)。
错误消息通常相当简洁这里的错误消息是相当不言自明的,您有一个查询
ORA-06550: line 57, column 5: PLS-00402: alias required in SELECT list of cursor to avoid duplicate column names
SELECT * FROM table1 t1 JOIN table2 t2 ON t1.something = t2.something
和
table1
和 table2
在两个表中都有具有相同标识符的列,并且 SELECT *
不知道如何命名相同的列。要修复此问题,请显式命名列,以便它们具有唯一的标识符/别名,并且不会有多个列尝试具有相同的标识符。