In general an ORA-00904 error means the database can't see the thing you are referring to. So either:
- It really doesn't exist, at least not the way you typed it. Check the spelling, look for it in the data dictionary (
all_objects etc) or where it's declared if it's a code item, check you're not referring to a procedure as if it's a function or vice versa, check whether any double-quoted identifiers are involved as these are case-sensitive.
- It really does exist, but your account can't see it. Check grants and synonyms, and make sure you are connected as the right user.
Regarding procedures vs functions, say you create a procedure called give_raise. Now you can call it like this:
begin
give_raise(123, 10);
end;
or this:
call give_raise(123, 10);
but not like this:
select give_raise(empno, 10) from employees;
because procedures and functions are two different things.
Regarding double-quoted identifiers, by default names are case-insensitive so you can refer to give_raise, GIVE_RAISE etc interchangeably, because the SQL parser and PL/SQL compiler internally uppercase everything as a first step. However, double-quotes make it case-sensitive (as well as allowing other normally invalid names such as "012 Crazy huh?"). If you name your procedure "GiveRaise" (in quotes) then that is how you must refer to it, quotes and all, forever.
Also, in Oracle SQL there are things you can and can't do to alias items. For example, you can refer to an alias in an order by clause:
select dummy as myalias from dual
order by myalias;
but not in a group by clause:
/* Invalid, gives ORA-00904: */
select dummy as myalias from dual
group by myalias;
Regarding privileges, note that standard definer-rights stored PL/SQL (create procedure etc) does not use roles, so even though you have logged in as JOE who has the HR_QUERY role, and Joe's SQL queries can access everything in HR, Joe's stored procedures can only see his own objects and anything directly granted to him (not via a role).
Regarding namespace issues, say that user HR has granted SELECT on EMPLOYEES to Joe. Joe still can't just select * from employees because he has to say where it is, rather like needing to specify the path in a filesystem, or dot notation in other languages. The default is the current schema, i.e. JOE.EMPLOYEES, which of course doesn't exist. Then the options are:
- Refer explicitly to
HR.EMPLOYEES (though hardcoding isn't ideal).
- Create a public synonym for
HR.EMPLOYEES (though can limit your options later due to the global nature of public synonyms, plus it broadcasts your object names which might be a security concern).
- Create a private synonym for
HR.EMPLOYEES in the JOE schema.
- Have Joe set his default schema to
HR using alter session set current_schema = HR.