【问题标题】:Query throws ORA-00904 Invalid Identifier when using joins使用连接时查询抛出 ORA-00904 Invalid Identifier
【发布时间】:2015-02-03 02:59:15
【问题描述】:

我遇到了一些奇怪的行为,这些行为使我无法以我想要的方式设置查询。将不胜感激任何想法。如果有任何有关表格的信息会有所帮助,请告诉我。我浏览了它们,没有任何可能导致这种情况的东西跳出来,但我也不知道我在寻找什么。这是行为。

这很好用:

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b,
    SCHEMA_C.TABLE_C c,
    SCHEMA_A.TABLE_D d
Where 
    b.friend_id = c.friend_id
    AND a.group_id = d.group_id
    AND b.group_cd = d.group_cd

但这会返回 ORA-00904: b.friend_id = c.friend_id: invalid identifier

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b,
    SCHEMA_A.TABLE_D d
Join 
    SCHEMA_C.TABLE_C c
On
    b.friend_id = c.friend_id
Where 
    a.group_id = d.group_id
    AND b.group_cd = d.group_cd

这将返回 ORA-00904: b.group_cd = d.group_cd: 标识符无效

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b
Join 
    SCHEMA_C.TABLE_C c
On
    b.friend_id = c.friend_id
Join 
    SCHEMA_A.TABLE_D d
On 
    a.group_id = d.group_id
    AND b.group_cd = d.group_cd

这又可以了:

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b
Join 
    SCHEMA_C.TABLE_C c
On
    b.friend_id = c.friend_id
Join 
    SCHEMA_A.TABLE_D d
On
    b.group_cd = d.group_cd
Where  
    a.group_id = d.group_id

【问题讨论】:

  • 这就是为什么您不应该将旧的 Oracle 类型的连接与适当的 ANSI 连接混合在一起,因为连接顺序和范围变得更加不清晰......坚持一个或另一个,最好是 ANSI * 8-)

标签: sql oracle


【解决方案1】:

尝试使用为 join 设计的 using 关键字在同一列名称上

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b
Join 
    SCHEMA_C.TABLE_C USING(friend_id)
Join 
    SCHEMA_A.TABLE_D d using(group_id)
where b.group_cd = d.group_cd;

同时确保您使用正确的用户执行其他查询,因为没有正确权限的用户将抛出 invalid identifier

编辑:实际的问题是你加入TABLE_CTABLE_D 但加入条件参考TABLE_B 将其更改为

Select * 
From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_A.TABLE_D d,
    SCHEMA_B.TABLE_B b
Join 
    SCHEMA_C.TABLE_C c using(friend_id)
Where 
    a.group_id = d.group_id
    AND b.group_cd = d.group_cd;

对其他查询应用相同的逻辑,在进行连接时,您不会连接到一组表,而是连接到from 子句中提到的最后一个表,因此它无权访问TABLE_B

对于可能出现invalid identifier 错误的其他人,请确保您的数据库不区分大小写,否则请确保使用正确的大小写。

【讨论】:

  • 他已经有成功运行的代码。他正在寻找不一致行为的解释。
  • 另一种可能性是区分大小写,但是您的两个查询的编写方式相同..
  • 就是这样。我没有意识到加入这样的工作,但现在它很有意义。非常感谢!仅供参考,我认为 USING 的问题在于它应该替换 ON,而不是遵循它
  • @philfo 是的,using 关键字不能有 ON 我的错误,我会编辑。
【解决方案2】:

我相信您已经遇到了处理连接范围/优先级的 SQL 的复杂性。由于我自己不是数据库程序员,因此我无法真正告诉您为什么它会以这种方式工作,但我确实看到了查询解析器的行为方式中的一些逻辑。

在您的第一个查询中,所有连接都是交叉连接。因此,它们应该具有相同的优先级。因此,在评估连接时,所有连接的列都是已知的。

在第二个查询中,您有交叉连接和内部连接的组合。如果我们假设内部连接优先于交叉连接,那么表 c 和 d 会在任何其他表添加到混合之前连接。因此,当您在内部联接之外的内部联接中引用 b.friend_id 时,查询解析器无法在评估联接时使用该列。

在第三个查询中,表 b、c 和 d 之间的内连接优先于交叉连接。因此,a.group_id 列在评估内部连接条件时不可用。当您在最终查询中从内部连接条件中取出表 a 时,该查询不再具有冲突的优先级。

【讨论】:

  • 它们并不是真正的交叉连接;使用旧的逗号分隔表语法,Oracle 使用where 条件作为连接条件。 (实际上它仍然可以与 ANSI 连接,但这是另一回事)。但是您仍然是对的,首先加入 C 和 D,然后 B 不在范围内。
  • 实际上,逗号分隔的表列表是一种隐含的交叉连接。见en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join。这就是为什么出于可读性和性能原因非常不鼓励这种做法的原因。
  • 来自同一页面:“交叉连接的结果可以通过使用 WHERE 子句进行过滤,然后可以产生等效的内部连接。”我同意这将是一个没有where 的交叉连接,但既然有一个,它就是一个内部连接——尽管当你使用 ANSI 术语来表示 Oracle 的语法时,术语会有点尴尬(甚至是 in the docs *8-)我'我在很大程度上分裂头发。
  • 您是正确的,返回的结果将与内部连接相同,但查询解析器到达该结果的方式可能大不相同。如果您正在处理一个非常大的数据集,必须加载所有记录,对所有记录应用交叉连接,然后过滤器将在内存中产生一个巨大的数据集。希望查询解析器将交叉连接优化为内部连接。如果是这样,那么你说它们是等价的是绝对正确的。除非有这种保证,否则我不会说与 WHERE 的交叉联接与内部联接相同。
  • @bluecollarcoder:在应用where 条件之前,它在逻辑上是一个交叉连接,但数据库不会以这种方式评估它。如果您查看来自 OP 的查询的解释计划,您将看不到笛卡尔积。长期以来,数据库一直在评估 where 子句中的连接,并在优化查询时将其考虑在内。
【解决方案3】:

这里的问题是连接类型的混合。当您在FROM 子句中使用逗号分隔表时,将单独评估每个术语。举个例子:

From 
    SCHEMA_A.TABLE_A a,
    SCHEMA_B.TABLE_B b,
    SCHEMA_A.TABLE_D d
Join 
    SCHEMA_C.TABLE_C c
On
    b.friend_id = c.friend_id

数据库正在尝试解析SCHEMA_A.TABLE_D d Join SCHEMA_C.TABLE_C c On b.friend_id = c.friend_id。在此范围内,b 没有任何意义(它是一个单独的术语)。

对于你的第三个版本,我得到了"A"."GROUP_ID": invalid identifier,这也符合这个解释。

最终你应该从中吸取的教训是不要混合连接类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多