Invalid column ORA- 00904 error while inserting into table from view - oracle

In my main table having table structure column without double quotes but when in View column with double quotes. While inserting data from view into table then getting error.
Here is the table structure of tbl
create table tbl (ID number(10),
name varchar2(50),
addr varchar2(200));
While View is-
create or replace view t_view as
select "ID", "name", "addr" from tbl;
While inserting data into tbl from t_view -
insert into tbl
select * from t_view;
Then getting error ORA- 00904: "addr": Invalid identifier.
So how to resolve this issue, can i remove the double quotes from creation of view.

Remove all double quotes from everywhere in your code.
If you use them while creating objects, you'll have to use them always, specifying exactly same letter case.
Get rid of those, Oracle is - by default - case insensitive and treats all names as uppercase (but you can reference them any way you want, just don't use double quotes!).

Oracle stores the name of any object in UPPERCASE by default. If you have provided double quotes then only Oracle stores the name of the object as it is.
Double quotes - Case sensitive
No quotes - Case insensitive - Stores the name in UPPERCASE
In your case, While writing the DDL of the table, you have not provided the name of the column in double quotes so your table name and column names are stored in UPPERCASE in the metadata.
You can see the same using the following query
select table_name, column_name from user_tab_columns where table_name = 'TBL';
For giving your answer, create the view either of the following syntaxes:
create or replace view t_view as
select ID, name, addr from tbl; -- no double quotes
create or replace view t_view as
select "ID", "NAME", "ADDR" from tbl; -- UPPERCASE column names in double quotes
See the demo here
Cheers!!

What is it you are trying to accomplish. Your request just doesn't make sense. Your intended statement
insert into tbl select * from t_view;
accomplishes exactly the same thing as
insert into tbl select * from tbl;
It's not that you cann't do this (you can), but it can only cause massive duplicate data issues or (hopefully) unique constraint violations.

Related

PL/SQL Trigger: Facing bad bind variable error

I have tried everything but nothing can solve this.PLS-00049: bad bind variable 'NEW.BLOODBANKID' keep appearing. Please help me.
CREATE OR REPLACE TRIGGER count_stock
AFTER INSERT OR UPDATE ON blood
FOR EACH ROW
DECLARE
v_countblood NUMBER;
BEGIN
SELECT COUNT(bloodid) INTO v_countblood
FROM blood
WHERE bloodbankid = :NEW.bloodbankid
AND bloodtype = :NEW.bloodtype;
IF v_countblood < 0 THEN
RAISE_APPLICATION_ERROR(-20201,'There is no blood');
END IF;
END;
The error indicates that there is no column "BLOODBANKID" in the table "BLOOD".
Either it doesn't exist at all in the table or you used double quotes on the column in your CREATE TABLE statement, thus making the column case sensitive.
If for instance your CREATE TABLE statement looks like this:
create table blood("bloodbankid" number(18), ...);
Then there is a column "bloodbankid" in the table, but no column "BLOODBANKID".
When we access a row without quotes as in
select BLOODBANKID from blood where BloodBankId = 123;
then Oracle converts this internally into "BLOODBANKID". As the same applies to CREATE TABLE, the column names usually match. If you used quotes in the CREATE TABLE statement, however, then you must use the same upper/lower case with quotes in every statement:
select "bloodbankid" from blood where "bloodbankid" = 123;
So, if this is the case, I'd recommend you re-create the table with case insensitive columns.
(Apart from this your trigger doesn't make sense anyway, as has already been mentioned in the request comments.)

BOUNDFILLER with select statement

In an Oracle Control File, can I populate a BOUNDFILLER from a lookup table?
for example:
EMPID BOUNDFILER "SELECT EMPID from employees where refno=refno"
I tried but I get an error msg, I assume because this is not possible?
The error message is: Expecting valid column specification, "," or ")", found ....
Any ideas of how I can populate a BOUNDFILLER from a lookup table?
EDIT: Apparently I am not very clear in what the issue is.
I need the BOUDFILLER to be populated from a lookup table. When the value is coming from the source file everything works well.
Thank you.
Here are a few more lines of code to visualize what I am trying to do:
EMPID BOUNDFILLER "(SELECT EMPID FROM table WHERE REFNO = :REFNBR)" (Trying to get empid from another table to use below)
EMPFIRSTNAME "(SELECT FIRST_NAME FROM table WHERE TRANS = :TRANS AND FILENAME =:FILENAME)"
EMPLASTNAME "(SELECT LAST_NAME FROM table WHERE TRANS = :TRANS AND FILENAME =:FILENAME)"
EMPEMAIL "(SELECT EMPEMAIL FROM table WHERE EMPID = :EMPID)"
EMPSUPERVISORNAME "(SELECT EMPSUPERVISORNAME FROM table WHERE EMPID = :EMPID)"
EMPHOMECITY "(SELECT EMPHOMEOFFICECITY FROM table WHERE EMPID = :EMPID)"
Any ideas of how I can populate a BOUNDFILLER from a lookup table?
You can't. (Despite the wording in the documentation kind of suggesting you should be able to; I think that's a doc bug and it should say something more like "Filler fields cannot be specified as part of another field specification's SQL string, because..." - and then the exception for BOUNDFILELR makes more sense).
If EMPID is not a field in your data file then you don't need a filler for it. If it is in the file but not in the target table you can skip it with a plain FILLER, unless you want to refer to that file value later too. If it is a column in your target table then you could use an EXPRESSION clause to do the look-up instead, but then you can't refer to that as a bind variable elsewhere.
If you want to refer to it in other SQL expressions for other columns in your control file then you'll need to repeat the lookup as a subquery in those.
For example, you could have:
REFNBR BOUNDFILLER,
EMPID EXPRESSION "(SELECT EMPID FROM lookuptable WHERE REFNBR = :REFNBR)",
EMPFIRSTNAME EXPRESSION "(SELECT FIRST_NAME FROM anothertable WHERE empid = (SELECT EMPID FROM lookuptable WHERE REFNO = :REFNBR))",
...
or slightly with a join:
REFNBR BOUNDFILLER,
EMPID EXPRESSION "(SELECT EMPID FROM lookuptable WHERE REFNBR = :REFNBR)",
EMPFIRSTNAME EXPRESSION "(SELECT t1.FIRST_NAME FROM lookuptable t1 JOIN anothertable t2 ON t2.empid = t1.empid WHERE t1.REFNBR = :REFNBR)",
...
I've declared them as EXPRESSION on the assumption that they don't have corresponding fields in the data file - essentially for these purposes that the data file only has REFNBR. (You may have other fields you haven't shown; you may even have fields correspondng to EMPID etc that you ignore - but in that case I'd treat those as FILLER and have independent EXPRESSION entries anyway to make it clear they aren't related.)
What you can't do is either supply a SQL expression as part of a BOUNDFILLER, or refer to one EXPRESSION in another field's SQL expression, i.e.:
REFNBR BOUNDFILLER,
EMPID EXPRESSION "(SELECT EMPID FROM lookuptable WHERE REFNBR = :REFNBR)",
EMPFIRSTNAME EXPRESSION "(SELECT FIRST_NAME FROM anothertable WHERE empid= :EMPID)",
...
as that will throw
SQL*Loader-291: Invalid bind variable EMPID in SQL string for column EMPFIRSTNAME.
The reason is kind of the same for both. From the documentation:
For each input record read, the value of the field referenced by the bind variable will be substituted for the bind variable.
It looks at the value of the field from the file, not after any transformation form a SQL expression. If you were only using REFNBR for that lookup then you might consider not referring to that directly at and doing:
EMPID "(SELECT EMPID FROM lookuptable WHERE REFNBR = :EMPID)",
EMPFIRSTNAME EXPRESSION "(SELECT FIRST_NAME FROM anothertable WHERE empid= :EMPID)",
...
but in the EXPRESSION evaluation it's still using the original value of the value from the file - i.e. actually a REFBNR - and not the final value that will be inserted as EMPID. So won't find a match, or won't match the row you intended, which is probably worse.
Given that, it wouldn't make sense for BOUNDFILLER to allow an SQL expression to be used - the result of that expression would never be used.
A couple of other thoughts... Clearly repeating the subquery/join is messy, so I can see why a reusable modified value would be useful in this scenario. But since you can't do that, it would be simpler to load the raw REFNBR (and any other fields you need from the file) into a staging table - either physical or an external table as #Littlefoot suggested - and then query that and join to the other tables to do a final insert into your target table.
And it looks - from what may be a very contrived example - like you're duplicating data, which may not be sensible; it might be better to actually just have REFNBR or at least just EMPID in your target table instead with referential constraints, so any changes made in anothertable are reflected automatically when it's queried. This may be part of a larger process that archives and deletes, or something; but then it would still be simpler to use a staging/external table and drive that whole process off that, instead of trying to make SQL*Loader do some of that work.
An alternative would be to switch to external table (behind the scene, it uses SQL*Loader). As it behaves as an "ordinary" table, you can write (PL/)SQL against it. It includes joins, subqueries, etc. so you'd be able to use that lookup table.

prevent sqldeveloper from expanding asterisc wildcard in view

I have two views, the second one depends on the data from the first and adds some columns from a different table.
In sql developer I define the views as follows:
view1:
select col11, col12, col13, col14, col15, col15, col16, col17
from table1
view2:
select view1.*, col22, col23
from view1 join table2 on view1.col11 = table2.col21
But when after saving, sqldeveloper expands the "view1.*" part of the second view to the explicit list of columns, so view2 ends up being rewritten as:
select view1.col11, view1.col12, view1.col13, view1.col14, view1.col15, view1.col15, view1.col16, view1.col17, col22, col23
from view1 join table2 on view1.col11 = table2.col21
which is harder to read and to mantain.
Is there a way to prevent this behavior?
Thanks
That's not SQL Developer doing that, it's the database.
You can create the view using the * syntax, but the database will always translate that to a fully qualified SELECT list.
CREATE VIEW LOCS
AS select * from locations;
Now ask the DB for the DDL, and you get
CREATE OR REPLACE FORCE EDITIONABLE VIEW "HR"."LOCS" (
"LOCATION_ID",
"STREET_ADDRESS",
"POSTAL_CODE",
"CITY",
"STATE_PROVINCE",
"COUNTRY_ID"
) AS
SELECT
"LOCATION_ID",
"STREET_ADDRESS",
"POSTAL_CODE",
"CITY",
"STATE_PROVINCE",
"COUNTRY_ID"
FROM
locations;
The view is defined at run-time, it'll take the existing column list and assume you want the same column names in your view as you want in the underlying objects where those columns are being pulled from.
From the Docs -
Expansion of Defining Queries at View Creation Time When a view is
created, Oracle Database expands any wildcard (*) in a top-level view
query into a column list. The resulting query is stored in the data
dictionary; any subqueries are left intact. The column names in an
expanded column list are enclosed in quote marks to account for the
possibility that the columns of the base object were originally
entered with quotes and require them for the query to be syntactically
correct.

Something unknown happened with a simple CREATE statement in Oracle 9i

One day, I accidently issued a CREATE statement on SQL prompt in Oracle 9i with all columns enclosing within double quotation marks as below.
CREATE TABLE emp("emp_id" VARCHAR2(6) primary key,
"emp_name" VARCHAR2(30) not null, "salary" NUMBER);
instead of issuing it as the one mentioned below without enclosing the column names within quotation marks as usual.
CREATE TABLE emp(emp_id VARCHAR2(6) primary key,
emp_name VARCHAR2(30) not null, salary NUMBER);
This simple query (first mentioned) worked just fine with no problem at all and the emp table was created successfully just then I have created three rows into this table with the following INSERT command.
INSERT INTO emp VALUES("E0001", "Henery", 50000);
INSERT INTO emp VALUES("E0002", "Alex", 65000);
INSERT INTO emp VALUES("E0003", "Peter", 70000);
Three rows created successfully into the emp table. I then executed a SELECT statement to verify whether they were created or not and found that they were indeed created.
SELECT * FROM emp;
but when I executed the SELECT statement like the one below
SELECT emp_id, emp_name, salary FROM emp;
I made sure that though, I had used the same column names as they were actually in the emp table, Oracle issued an error indicating that "Such columns don't exist."
From the SQL Language Reference:
"A quoted identifier begins and ends with double quotation marks (").
If you name a schema object using a quoted identifier, then you must
use the double quotation marks whenever you refer to that object."

Creating a view using subquery,with alias for columns in ORACLE 9i!

This is my query,
CREATE VIEW employee_vu AS(
SELECT employee_id,last_name "employee",department_id
FROM employees);
I am giving alias of columns in lower case ,and in it is stored in lower case
after doing desc i have confirmed.
But when i am trying to select this column employee :error occurs
EMPLOYEE: invalid identifier
Since all column name is stored in upper case ,is this the problem,Please explain what is the concept behind!
You would need to select it using double quotes and matching case:
select employee_id, "employee", department_id from employees;
That's why creating columns with double quoted identifiers is considered bad practice in Oracle.

Resources