我的老板在我创建的查询中发现了一个错误,我不明白错误背后的原因,尽管查询结果证明他是正确的。这是修复之前的查询(简化版):
select PTNO,PTNM,CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
这里是修复之后:
select PTNO,PTNM,PARTS.CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
错误是,列CATCD显示空值,即查询结果包括表CATEGORIES而不是PARTS的结果。 这是我不明白的:如果原始查询中存在歧义,为什么Oracle没有抛出错误?据我所知,在左连接的情况下,查询(PARTS)中的“主”表优先于歧义。 我错了,还是没有正确地考虑这个问题?
更新
这是一个修改过的例子,其中没有抛出歧义错误:
CREATE TABLE PARTS (PTNO NUMBER, CATCD NUMBER, SECCD NUMBER);
CREATE TABLE CATEGORIES(CATCD NUMBER);
CREATE TABLE SECTIONS(SECCD NUMBER, CATCD NUMBER);
select PTNO,CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD)
left join SECTIONS on (SECTIONS.SECCD=PARTS.SECCD) ;
有人有线索吗?
答案 0 :(得分:6)
这是查询(简化版)
我认为通过简化查询,您删除了错误的真正原因: - )
您使用的是哪个oracle版本? Oracle 10g(10.2.0.1.0)给出了:
create table parts (ptno number , ptnm number , catcd number);
create table CATEGORIES (catcd number);
select PTNO,PTNM,CATCD from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
我得到ORA-00918:列模糊定义
答案 1 :(得分:2)
有兴趣抛出错误的SQL服务器(应该如此)
select id
from sysobjects s
left join syscolumns c on s.id = c.id
服务器:消息209,级别16,状态1,行1 不明确的列名'id'。
select id
from sysobjects
left join syscolumns on sysobjects.id = syscolumns.id
服务器:消息209,级别16,状态1,行1 不明确的列名'id'。
答案 2 :(得分:2)
根据我的经验,如果您创建这样的查询,当存在像这样的字段重叠时,数据结果将从连接的右侧而不是左侧拉出CATCD。
因为这个连接将包含来自PARTS的所有记录,只有一些来自CATEGORIES的记录,只要右侧没有数据,你就会在CATCD字段中得到NULL。
通过从PARTS(即左侧)明确定义列,您将获得非空值,假设该字段在PARTS中具有数据。
请记住,对于LEFT JOIN,您只是左表中字段中的保证数据,右侧可能是空列。
答案 3 :(得分:2)
这可能是Oracle优化器中的错误。我可以使用3个表在查询上重现相同的行为。直观地看起来它应该产生错误。如果我用以下任何一种方法重写它,它确实会产生错误:
(1)使用旧式外连接
select ptno, catcd
from parts, categories, sections
where categories.catcd (+) = parts.catcd
and sections.seccd (+) = parts.seccd
(2)明确隔离两个连接
select ptno, catcd
from (
select ptno, seccd, catcd
from parts
left join categories on (categories.CATCD=parts.CATCD)
)
left join sections on (sections.SECCD=parts.SECCD)
我使用DBMS_XPLAN来获取有关查询执行的详细信息,这确实显示了一些有趣的内容。该计划基本上是外部加入PARTS和CATEGORIES,项目结果集,然后外部连接到SECTIONS。有趣的是,在第一个外连接的投影中,它只包括PTNO和SECCD - 它不包括前两个表中任何一个的CATCD。因此,最终结果是从第三个表中获取CATCD。
但我不知道这是一个原因还是影响。
答案 4 :(得分:1)
我正在使用Oracle 9.2.0.8.0。它确实给出错误“ORA-00918:列模糊定义”。
答案 5 :(得分:1)
我担心我不能告诉你为什么你没有得到例外,但我可以假设为什么它选择了CATTSORIES版本的专栏而不是PARTS版本。
据我所知,在左连接的情况下,查询(PARTS)中的“主”表优先于歧义
目前尚不清楚“main”是指简单地表示左连接中的左表,还是“驱动”表,正如您在概念上看到的那样...但在任何一种情况下,您所看到的都是“主” “在您编写查询时,表格不一定是该查询实际执行中的”主“表。
我的猜测是Oracle只是使用它在执行查询时遇到的第一个表中的列。而且由于SQL中的大多数单独操作都不需要在另一个表之前命中一个表,因此DBMS将在解析时决定哪个是最先扫描的。尝试获取查询的执行计划。我怀疑它可能会显示它首先击中了CATEGORIES,然后是PARTS。
答案 6 :(得分:1)
这是使用ANSI样式连接时某些Oracle版本的已知错误。正确的行为是获得ORA-00918错误。
无论如何最好指定你的表名;这样,当您碰巧添加一个名称也在另一个表中使用的新列时,您的查询不会中断。
答案 7 :(得分:0)
通常建议您具体并完全限定所有列名称,因为它可以为优化器节省一些工作量。当然在SQL Server中。
从Oracle docs中可以看出,如果你在选择列表中选择两次列名,或者在选择列表中选择一次,然后在其他地方再次使用order by子句,它就会抛出。
也许你已经发现了一个'未记录的功能':)
答案 8 :(得分:0)
与HollyStyles一样,我在Oracle文档中找不到可以解释你所看到的内容的任何内容。
PostgreSQL,DB2,MySQL和MSSQL都拒绝运行第一个查询,因为它不明确。
答案 9 :(得分:0)
@Pat:我的查询中出现同样的错误。我的查询比我最初发布的内容稍微复杂一点。我现在正在研究一个可重现的简单例子。
答案 10 :(得分:0)
你应该问自己一个更大的问题是 - 为什么我在零件表中有一个类别代码中没有的类别代码?
答案 11 :(得分:0)
这是Oracle 9i中的一个错误。如果使用ANSI表示法加入2个以上的表,则不会检测列名中的歧义,如果未使用别名,则可能返回错误的列。
如前所述,它固定为10g,因此如果不使用别名,将返回错误。