BOUNDFILLER with select statement - oracle

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.

Related

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

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.

Oracle query to get the results of a particular table using the result obtained from another table

I am new to Oracle, so kindly bear with me if the question sounds really naive.
So, I have two tables TableA and TableB which have say just two columns id, name for simplicity.
I now want to now get the id value for a particular value of name in TableA. If this would be the only requirement, this query would suffice -
SELECT id from TableA WHERE name = 'some_name';
Now, what I want to do is take this id and delete all the rows in TableB that match this id-
DELETE FROM TableB WHERE id = <id obtained from the above query>;
What is the composite query in oracle that would perform this function?
Thanks!
If you know that only a single id value is going to be returned for a particular name value, you'd just do
DELETE FROM tableB b
WHERE b.id = (SELECT a.id
FROM tableA a
WHERE a.name = 'some_name')
Note that the aliases are optional. However, adding aliases generally makes things clearer so no one has to guess which id or which name you're referring to at any point.
If there might be multiple id values in tableA for a given name, you'd just use an IN rather than an =
DELETE FROM tableB b
WHERE b.id IN (SELECT a.id
FROM tableA a
WHERE a.name = 'some_name')
This would also work if you knew that the query against tableA was only going to return one row. I'd prefer the equality query if you're sure that only one row would be returned, though. I'd generally rather get an error if my expectations were violated rather than potentially having unexpected rows get deleted.

how to pass parameter to oracle update statement from csv file and excluding null values from csv

I have a situation where I have following csv file(say file.csv) with following data:
AcctId,Name,OpenBal,closingbal
1,abc,1000,
2,,0,
3,xyz,,
4,,,
how can I loop through this file using unix shell and say for example for column $2 (Name) , I want to get all occurances of Name column accept null values and pass it to for example following oracle query with single quotes '','' format?
select * from account
where name in (collection of values from csv file column name
but excluding null values)
and openbal in
and same thing for column 3 (collection of values from csv file column Openbal
but excluding null values)
and same thing for column 4 (collection of values from csv file column
closingbal but excluding null values)
In short what I want is pass the csv column values as input parameter to oracle sql query and update query too ? but again I dont want to include null values in it. If a column is entirely null for all rows I want to exclude it too?
Not sure why you'd want to loop through this file in a unix shell script: perhaps because you can't think of any better approach? Anyway, I'm going to skip that and offer a pure Oracle solution.
We can expose data in CSV files to the database using external tables. These are like regular tables except their data comes from files in OS directories on the database server (rather than the database's storage). Find out more.
Given this approach it is easy to write the query you want. I suggest using sub-query factoring to select from the external table once.
with cte as ( select name, openbal, closingbal
from your_external_tab )
select *
from account a
where a.name in ( select cte.name from cte )
and a.openbal in ( select cte.openbal from cte )
and a.closingbal in ( select cte.closingbal from cte )
The behaviour of the IN clause is to exclude NULL from consideration.
Incidentally, that will return a different (larger) result set from this:
select a.*
from account a
, your_external_table e
where a.name = e.name
and a.openbal= e.openbal
and a.closingbal = e.closingbal

Column name is masked in oracle indexes

I have a table in oracle db which has a unique index composed of two columns (id and valid_from). The column valid_from is of type timestamps with time zone.
When I query the SYS.USER_IND_COLUMNS to see which columns my table is using as unique index, I can not see the name of the valid_from column but instead I see smth like SYS_NC00027$.
Is there any possibility that I can display the name valid_from rather than SYS_NC00027$. ?
Apparently Oracle creates a function based index for timestamp with time zone columns.
The definition of them can be found in the view ALL_IND_EXPRESSIONS
Something like this should get you started:
select ic.index_name,
ic.column_name,
ie.column_expression
from all_ind_columns ic
left join all_ind_expressions ie
on ie.index_owner = ic.index_owner
and ie.index_name = ic.index_name
and ie.column_position = ic.column_position
where ic.table_name = 'FOO';
Unfortunately column_expression is a (deprecated) LONG column and cannot easily be used in a coalesce() or nvl() function.
Use the below to verify the col info.
select column_name,virtual_column,hidden_column,data_default from user_tab_cols where table_name='EMP';

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