ORA-00904: 无效标识符

113

我尝试在Oracle数据库中编写以下内部连接查询语句:

 SELECT Employee.EMPLID as EmpID, 
        Employee.FIRST_NAME AS Name,
        Team.DEPARTMENT_CODE AS TeamID, 
        Team.Department_Name AS teamname
 FROM PS_TBL_EMPLOYEE_DETAILS Employee
 INNER JOIN PS_TBL_DEPARTMENT_DETAILS Team 
 ON Team.DEPARTMENT_CODE = Employee.DEPTID

这会导致以下错误:

 INNER JOIN PS_TBL_DEPARTMENT_DETAILS Team ON Team.DEPARTMENT_CODE = Employee.DEPTID
                                              *
ERROR at line 4:
ORA-00904: "TEAM"."DEPARTMENT_CODE": invalid identifier

一个表的DDL是:

CREATE TABLE "HRMS"."PS_TBL_DEPARTMENT_DETAILS"
(
  "Company Code" VARCHAR2(255),
  "Company Name" VARCHAR2(255),
  "Sector_Code" VARCHAR2(255),
  "Sector_Name" VARCHAR2(255),
  "Business_Unit_Code" VARCHAR2(255),
  "Business_Unit_Name" VARCHAR2(255),
  "Department_Code" VARCHAR2(255),
  "Department_Name" VARCHAR2(255),
  "HR_ORG_ID" VARCHAR2(255),
  "HR_ORG_Name" VARCHAR2(255),
  "Cost_Center_Number" VARCHAR2(255),
  " " VARCHAR2(255)
)
SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS

你确定列名 Department_Code 拼写正确吗? - Fabrizio D'Ammassa
是的,有一个名为Department_Code的列。 - Navaneethan
15
TL;DR: 使用单引号 '' - Andrew
在我的情况下,这是一个在数据库中不存在的计算列。 - abdoulsn
我不得不在Snowflake中使用双引号。 - alluppercase
14个回答

163

你的问题在于那些讨厌的双引号。

SQL> CREATE TABLE "APC"."PS_TBL_DEPARTMENT_DETAILS"
  2  (
  3    "Company Code" VARCHAR2(255),
  4    "Company Name" VARCHAR2(255),
  5    "Sector_Code" VARCHAR2(255),
  6    "Sector_Name" VARCHAR2(255),
  7    "Business_Unit_Code" VARCHAR2(255),
  8    "Business_Unit_Name" VARCHAR2(255),
  9    "Department_Code" VARCHAR2(255),
 10    "Department_Name" VARCHAR2(255),
 11    "HR_ORG_ID" VARCHAR2(255),
 12    "HR_ORG_Name" VARCHAR2(255),
 13    "Cost_Center_Number" VARCHAR2(255),
 14    " " VARCHAR2(255)
 15  )
 16  /

Table created.

SQL>

Oracle SQL允许我们忽略数据库对象名称的大小写,前提是我们要使用全大写的名称创建它们或者不使用双引号。如果我们在脚本中使用混合大小写或小写,并将标识符用双引号括起来,那么我们就不得不在引用对象或其属性时使用双引号和精确的大小写:

SQL> select count(*) from PS_TBL_DEPARTMENT_DETAILS
  2  where Department_Code = 'BAH'
  3  /
where Department_Code = 'BAH'
      *
ERROR at line 2:
ORA-00904: "DEPARTMENT_CODE": invalid identifier


SQL> select count(*) from PS_TBL_DEPARTMENT_DETAILS
  2  where "Department_Code" = 'BAH'
  3  /

  COUNT(*)
----------
         0

SQL>

简而言之:

在DDL脚本中不要使用双引号。

(虽然我知道大多数第三方代码生成器都会这样做,但是它们有纪律性,会将所有对象名都写成大写字母形式。)


反过来也是一样的。如果我们创建表时没有使用双引号...

create table PS_TBL_DEPARTMENT_DETAILS
( company_code VARCHAR2(255),
  company_name VARCHAR2(255),
  Cost_Center_Number VARCHAR2(255))
;

我们可以引用它以及其中的列,无论使用什么大小写都可以:

select * from ps_tbl_department_details

…或者

select * from PS_TBL_DEPARTMENT_DETAILS;

...或者

select * from PS_Tbl_Department_Details
where COMAPNY_CODE = 'ORCL'
and cost_center_number = '0980'

42
“有害”这个词甚至无法形容Oracle这些非标准惯例所带来的沮丧程度。 - Don Scott
3
Oracle很糟糕。可怕的程序。 - Brian
我正在进行一个混合连接查询的Oracle数据库链接练习,这正是我的问题所在。我一直收到“ORA-00904: "A"."NOMBRE": invalid identifier”等错误提示,问题得以解决是因为在出现错误的列名中添加了双引号。 - Adrián Jaramillo

17
在我的情况下,这个错误是由于表中缺少列名导致的。 当我执行“describe tablename”时,在映射hbm文件中指定的列名并不存在。 在修改表后,问题得到解决。

1
另一个情况是整张表缺失。 - Haoyu Chen

5

在这种情况下,原因被发现是DDL中混合大小写的列名导致的。

然而,如果你在混用“旧式”的连接方式和ANSI连接方式,即使DDL正确使用大写表名,也可能会遇到相同的错误信息。我自己就碰到了这种情况,然后谷歌把我送到了这个stackoverflow页面,所以我觉得应该分享一下。

--NO PROBLEM: ANSI syntax
SELECT A.EMPLID, B.FIRST_NAME, C.LAST_NAME
FROM PS_PERSON A
INNER JOIN PS_NAME_PWD_VW B ON B.EMPLID = A.EMPLID
INNER JOIN PS_HCR_PERSON_NM_I C ON C.EMPLID = A.EMPLID
WHERE 
    LENGTH(A.EMPLID) = 9
    AND LENGTH(B.LAST_NAME) > 5
    AND LENGTH(C.LAST_NAME) > 5
ORDER BY 1, 2, 3
/

--NO PROBLEM: OLD STYLE/deprecated/traditional oracle proprietary join syntax
SELECT A.EMPLID, B.FIRST_NAME, C.LAST_NAME
FROM PS_PERSON A
, PS_NAME_PWD_VW B 
, PS_HCR_PERSON_NM_I C 
WHERE 
    B.EMPLID = A.EMPLID
    and C.EMPLID = A.EMPLID
    and LENGTH(A.EMPLID) = 9
    AND LENGTH(B.LAST_NAME) > 5
    AND LENGTH(C.LAST_NAME) > 5
ORDER BY 1, 2, 3
/

以上两个SQL语句是等价的,不会产生错误。

当你尝试混合使用它们时,有可能会幸运地成功,或者会出现Oracle的ORA-00904错误。

--LUCKY: mixed syntax (ANSI joins appear before OLD STYLE)
SELECT A.EMPLID, B.FIRST_NAME, C.LAST_NAME
FROM 
    PS_PERSON A
    inner join PS_HCR_PERSON_NM_I C on C.EMPLID = A.EMPLID
    , PS_NAME_PWD_VW B
WHERE 
    B.EMPLID = A.EMPLID
    and LENGTH(A.EMPLID) = 9
    AND LENGTH(B.FIRST_NAME) > 5
    AND LENGTH(C.LAST_NAME) > 5
/

--PROBLEM: mixed syntax (OLD STYLE joins appear before ANSI)
--http://sqlfascination.com/2013/08/17/oracle-ansi-vs-old-style-joins/
SELECT A.EMPLID, B.FIRST_NAME, C.LAST_NAME
FROM 
    PS_PERSON A
    , PS_NAME_PWD_VW B
    inner join PS_HCR_PERSON_NM_I C on C.EMPLID = A.EMPLID
WHERE 
    B.EMPLID = A.EMPLID
    and LENGTH(A.EMPLID) = 9
    AND LENGTH(B.FIRST_NAME) > 5
    AND LENGTH(C.LAST_NAME) > 5
/

以下是一个并不真正描述问题的无用错误信息:

>[Error] Script lines: 1-12 -------------------------
ORA-00904: "A"."EMPLID": invalid identifier  Script line 6, statement line 6,
column 51 

我能在以下博客文章中找到有关此问题的一些研究: 在我的情况下,我尝试手动从旧式连接转换为ANSI样式连接,并逐个表进行。这似乎是一个不好的主意。相反,最好一次性转换所有表,或注释原始查询中的一个表及其where条件,以便与您正在编写的新的ANSI查询进行比较。

4
在我的情况下,当我尝试像这样在Oracle中创建一个新表时,最后一行带有,,导致出现了这个错误。
create table products(
  id_pro number primary key,
  product_name varchar2(20),
);

通过去除,,问题可以得到解决

create table products_test(
  id_pro number primary key,
  product_name varchar2(20)
);

4

DEPARTMENT_CODE不是Team表中存在的列。请检查表的数据定义语言(DDL)以找到正确的列名。


1
该列存在于表中,我已经进行了检查。 - Navaneethan
1
你能给我们提供表PS_TBL_DEPARTMENT_DETAILS的DDL吗? - Datajam
1
创建表格 "HRMS"."PS_TBL_DEPARTMENT_DETAILS" ( "公司代码" VARCHAR2(255), "公司名称" VARCHAR2(255), "部门代码" VARCHAR2(255), "部门名称" VARCHAR2(255), "业务单元代码" VARCHAR2(255), "业务单元名称" VARCHAR2(255), "部门代码" VARCHAR2(255), "部门名称" VARCHAR2(255), "HR_ORG_ID" VARCHAR2(255), "HR_ORG_Name" VARCHAR2(255), "成本中心编号" VARCHAR2(255), " " VARCHAR2(255) ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRES - Navaneethan
4
如果那确实是DDL,那么列已经被创建为区分大小写。你应该从列定义中删除双引号。如果你无法重新创建表格,在你的选择语句中使用Team."Department_Name"。 - Datajam
4
我特别喜欢最后一列的名称;你猜存储在那里的是什么? - Alex Poole
显示剩余3条评论

3

在尝试通过JPA保存实体时,我遇到了这个错误。

原因是我有一个带有 @JoinColumn 注释的列没有带有 @ManyToOne 注释。

添加 @ManyToOne 注释修复了这个问题。


2
你确定你的表格 PS_TBL_DEPARTMENT_DETAILS 上有一个列名为 DEPARTEMENT_CODE 的字段吗?
关于你的错误,请查看更多信息

ORA-00904: string: 无效标识符 原因:输入的列名不存在或无效。 操作:请输入有效的列名。有效的列名必须以字母开头, 长度小于等于30个字符,只能由字母、数字和特殊字符$、_和#组成。 如果它包含其他字符,则必须用双引号括起来。 它不能是保留字。


1

同时确保发出查询的用户已被授予必要的权限。

对于表格查询,您需要授予SELECT权限。
对于其他对象类型(例如存储过程)的查询,您需要授予EXECUTE权限。


1
虽然检查授予权限通常是值得的,但如果您缺少表格授予权限,则更有可能遇到著名且同样有用的ORA-00942表或视图不存在错误。 - real_paul
select some_column from some_table where some_package.some_function() = 0的情况下,当当前用户没有为某个包授予execute权限时,我观察到ORA-00904错误。(Ora 11g,通过Hibernate调用) - Tomáš Záluský

1
我遇到了同样的异常和问题,原因是子查询中缺少了某个列 - 尽管我知道“缺失”的列/标识符属于我引用的别名表。
例如 - 这个查询在列MC.SIT_TYPE处生成了ORA-00904 - 无效标识符
SELECT MC.ID_CODE,
       MC.EMP_NAME
FROM (SELECT MC.ID_CODE, 
             MC.EMP_NAME
      FROM EMP_WORKER MC) MC
INNER JOIN TEM_SHEETS FR ON MC.SIT_TYPE = FR.ID_CODE -- This line has the ORA-00904 error.
LEFT JOIN WRK_TYPE RAS ON MC.ID_CODE = RAS.ID_CODE;

现在,通过添加MC.SIT_TYPE列来修改子查询后,ORA-00904错误已消失。

结果:

SELECT MC.ID_CODE,
       MC.EMP_NAME
FROM (SELECT MC.ID_CODE, 
             MC.EMP_NAME, ​
            ​ -- Here, the "missing invalid identifier, in this case (MC.SIT_TYPE)" is added: 
             MC.SIT_TYPE
      FROM EMP_WORKER MC) MC
INNER JOIN TEM_SHEETS FR ON MC.SIT_TYPE = FR.ID_CODE 
LEFT JOIN WRK_TYPE RAS ON MC.ID_CODE = RAS.ID_CODE;

以下是一些提示:
  • 非常仔细地检查您的代码的缩进/对齐 - (根据您的设置),SQL Developer处理代码的缩进不同。
  • 您正在处理的代码可能没有进行缩进 - 这会使这种错误的调试变得更加困难和耗时。
  • 修改列/子查询的别名 - 通常的代码 - 以生成唯一的别名 - 我的意思是:不要使用相同的别名用于子查询和相关表。

0

我之前传递的数值没有加引号。一旦我将条件放在单引号内传递,它就像魔法般地奏效了。

Select * from emp_table where emp_id=123;

不要使用上述内容,而要使用以下内容:

Select * from emp_table where emp_id='123';

如果 emp_id 是一个数字,第一条语句将会引发 ORA-01722: invalid number 错误。 - René Nyffenegger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接