How to get all XML file names from a directory using EXTERNAL TABLE - oracle

I am trying to get all XML file names present in a directory in order to feed them to a procedure which pulls data out of those files. Could anyone help with how I can get the file name using the EXTERNAL TABLE.
I am having trouble with ACCESS PARAMETERS and LOCATION file. Don't know what exactly would go there.
Thanks
CREATE TABLE S7303786.XML_FILES
(
FILE_NAME VARCHAR2(255 CHAR)
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY AUTOACCEPT_XMLDIR
ACCESS PARAMETERS
(
RECORDS DELIMITED BY NEWLINE
PREPROCESSOR AUTOACCEPT_XMLDIR: 'list_file.sh'
FIELDS TERMINATED BY WHITESPACE
)
LOCATION ('list_file.sh')
)
REJECT LIMIT UNLIMITED;
list_files.sh just contains the directory where the files are present.
sticky.txt has nothing in it
error I am getting are :
ORA-29913: error in executing ODCIEXTTABLEFETCH callout
ORA-29400: data cartridge error
KUP-04004: error while reading file /home/transfer/stu/nshstrans/sticky.txt

Error you got might have something to do with directory, Oracle object which points to physical directory on database server's disk. It is created by a privileged user - SYS, who then grants read and/or write privileges on it to users who will use it.
If you missed to do anything of above mentioned things, your external table won't work.
So:
SQL> show user
USER is "SYS"
SQL>
SQL> create directory mydir as 'c:\temp';
Directory created.
SQL> grant read, write on directory mydir to scott;
Grant succeeded.
SQL>
Connect to Scott and create external table:
SQL> connect scott/tiger
Connected.
SQL> create table extusers
2 (username varchar2(20),
3 country varchar2(20)
4 )
5 organization external
6 (type oracle_loader
7 default directory mydir --> this is directory I created
8 access parameters
9 (records delimited by newline
10 fields terminated by ';'
11 missing field values are null
12 (username char(20),
13 country char(20)
14 )
15 )
16 location ('mydata.txt') --> name of the file that contains data
17 ) -- located in c:\temp, which is MYDIR
18 reject limit unlimited -- directory
19 /
Table created.
SQL>
Contents of the sample text file:
SQL> $type c:\temp\mydata.txt
Littlefoot;Croatia
Michel;France
Maaher;Netherlands
SQL>
Finally, let's select from the external table:
SQL> select * from extusers;
USERNAME COUNTRY
-------------------- --------------------
Littlefoot Croatia
Michel France
Maaher Netherlands
SQL>
Works OK, doesn't it? Now, try to do what I did.
On a second reading,
it appears that you don't want to read file contents, but directory contents. If that's so - apparently, it is - then see whether this helps.
In order to make it work, privileged user has to grant additional privilege - EXECUTE - to the directory.
SQL> show user
USER is "SYS"
SQL> grant execute on directory mydir to scott;
Grant succeeded.
Next step is to create an operating system executable (on MS Windows I use, it is a .bat script; on Unix, that would be a .sh, I think) which will list the directory. Note the first line - I have to navigate to a directory which is source for Oracle directory object. If you don't do that, it won't work. The .bat file is simple:
SQL> $type c:\temp\directory_contents.bat
cd c:\temp
dir /b *.txt
SQL>
Create external table:
SQL> create table extdir
2 (line varchar2(50))
3 organization external
4 (type oracle_loader
5 default directory mydir
6 access parameters
7 (records delimited by newline
8 preprocessor mydir:'directory_contents.bat'
9 fields terminated by "|" ldrtrim
10 )
11 location ('directory_contents.bat')
12 )
13 reject limit unlimited
14 /
Table created.
SQL> connect scott/tiger
Connected.
Let's see what it returns:
SQL> select * From extdir;
LINE
-----------------------------------------------
c:\Temp>dir /b *.txt
a.txt
dept.txt
emp.txt
emps.txt
externalfile1.txt
lab18.txt
mydata.txt
p.txt
parfile_01.txt
sofile.txt
test.txt
test2.txt
15 rows selected.
SQL>
Well ... yes, those are my .txt files located in c:\temp directory.
As you use *nix, I think that problem you got is related to list_files.sh script. You didn't post its contents (which would probably help - not necessarily help me as I forgot almost everything I knew about *.nix), but - regarding Preprocessing External Tables (written by Michael McLaughlin), you might need to
prepend /usr/bin before the ls, find, and sed programs: /usr/bin/ls ...
See if it helps.

Related

Creating directory direct from oracle [duplicate]

How do you create a physical directory on the OS from within PL/SQL? I looked at the CREATE OR REPLACE DIRECTORY command but that doesn't do it. Neither does UTL_FILE appear to be capable.
In the end I did find an easier solution. Use
select os_command.exec('mkdir /home/oracle/mydir') from dual;
or simply
x := os_command.exec('mkdir /home/oracle/mydir');
UTL_FILE still lacks this capability - probably a holdover from the pre-DIRECTORY object days where you had to explicitly define the OS file directories you could access in a startup parameter, so there was no need to create directories dynamically anyway.
I think the easiest way to do this is with an Oracle Java stored procedure that uses:
File f = new File(dirname);
return (f.mkdir()) ? 1 : 0;
If you go this route make sure that you use dbms_java.grant_permission to grant java.io.FilePermission to the user that owns the executing code.
I believe the only way to do this is to use an external procedure (C or Java) and call it through PL/SQL. PL/SQL itself does not have the means to create the physical OS directory.
PL/SQL Tips provides a good example of how to create a C external procedure that executes shell commands. Note that I would not consider it best practice to allow this for security reasons.
It you can create the directory first, then you can use the
create or replace directory myDir as '<path-to-dir>/myDir';
Note that you will need to have the CREATE ANY DIRECTORY privilege assigned to the user executing the command. After the directory is created with the command above, be sure to assign any needed privileges on the directory to other users.
grant read, write on directory myDir to testUsers;
I just checked the new docs for database version 11.2, and there's still no routine I can find to create a directory. So, like the other respondents, I recommend using a Java or C routine.
You can execute OS commands from within Oracle using DBMS_SCHEDULER or internal Java procedure, for example, using my XT_SHELL package:
install it using install.sql:
Execute OS command using xt_shell.shell_exec(pCommand in varchar2,timeout in number) in SQL or PL/SQL:
SQL> select * from table(xt_shell.shell_exec('/bin/mkdir /tmp/test-dir',1000));
COLUMN_VALUE
--------------------------------------------------------------------------------
SQL> select * from table(xt_shell.shell_exec('/bin/mkdir /tmp/test-dir/test-dir2',1000));
COLUMN_VALUE
--------------------------------------------------------------------------------
SQL> select * from table(xt_shell.shell_exec('/bin/ls -l /tmp/test-dir',1000));
COLUMN_VALUE
--------------------------------------------------------------------------------
total 4
drwxr-xr-x 2 oracle oinstall 4096 Apr 19 12:14 test-dir2

Import data from file.txt to table Oracle SQL using PL/SQL

I'm trying to read a file of type txt from c:\Dir and insert the content on the table Oracle Sql
set SERVEROUTPUT ON
CREATE OR REPLACE DIRECTORY MYDIR AS ' C:\dir';
DECLARE
vInHandle utl_file.file_type;
eNoFile exception;
PRAGMA exception_init(eNoFile, -29283);
BEGIN
BEGIN
vInHandle := utl_file.Fopen('MYDIR','attachment.txt','R');
dbms_output.put_line('The File exists');
EXCEPTION
WHEN eNoFile THEN
dbms_output.put_line('The File not exists');
END;
END fopen;
/
i have the file not exists but i have this file
I don't know whether space you have in front of the directory name in the first statement you posted makes difference (or is it just a typo), but - nonetheless, here's how it is usually done.
Create directory on hard disk:
C:\>mkdir c:\dir
Connect to the database as SYS (as it owns the database, as well as directories); create directory (Oracle object) and grant privileges to user which will use that directory:
C:\>sqlplus sys as sysdba
SQL*Plus: Release 11.2.0.2.0 Production on ╚et O×u 5 18:34:43 2020
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Enter password:
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL> create or replace directory mydir as 'c:\dir';
Directory created.
SQL> grant read, write on directory mydir to scott;
Grant succeeded.
SQL>
You don't need this, as you already have the file; I'll create it by spooling table contents.
SQL> connect scott/tiger
Connected.
SQL> spool c:\dir\example.txt
SQL> select * From dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> spool off;
SQL> $dir c:\dir\*.txt
Volume in drive C is OSDisk
Volume Serial Number is 7635-F892
Directory of c:\dir
05.03.2020. 18:39 539 example.txt
1 File(s) 539 bytes
0 Dir(s) 290.598.363.136 bytes free
SQL>
Finally, reusing code you wrote:
SQL> set serveroutput on
SQL>
SQL> DECLARE
2 vInHandle utl_file.file_type;
3 eNoFile exception;
4 PRAGMA exception_init(eNoFile, -29283);
5 BEGIN
6 BEGIN
7 vInHandle := utl_file.Fopen('MYDIR','example.txt','R');
8 dbms_output.put_line('The File exists');
9 EXCEPTION
10 WHEN eNoFile THEN
11 dbms_output.put_line('The File not exists');
12 END;
13 END fopen;
14 /
The File exists
PL/SQL procedure successfully completed.
SQL>
Works properly (congratulations, you wrote code that actually works!).
So, what have you done wrong?
as I said, space in front of c:\dir: CREATE OR REPLACE DIRECTORY MYDIR AS ' C:\dir';
database isn't on your computer but on a separate database server
it means that you probably created directory, but it points to c:\dir directory on the database server, not your own PC!
As Boneist commented, it is possible to create a directory (Oracle object) on computer which is NOT a database server, but that's not something we usually do. If you opt to choose this option, you'll have to use UNC (Universal Naming Convention) while creating directory.
Another option you might want to consider is to use SQL Loader. It is an operating system utility, installed along with the database or (full, not instant) client software. Its advantage is that it runs on your local PC (i.e. you don't have to have access to the database server) and is extremely fast. You'd create a control file which tells Oracle how to load data stored in the source (.txt) file.
Another option, which - in the background - uses SQL Loader, is to use an external table. It is yet another Oracle object which points to the source (.txt) file and allows you to access it using a simple SQL SELECT statement. Possible drawback: it still requires access to the Oracle directory (just like your UTL_FILE option).

ORA-29913: error in executing ODCIEXTTABLEOPEN callout when inserting csv into oracle

I'm trying to execute this code in PL/SQL:
create or replace directory ext_tab_dir as 'C:/mydir';
GRANT READ,WRITE ON DIRECTORY ext_tab_dir TO PUBLIC;
DROP TABLE emp_load;
CREATE TABLE emp_load (v1 VARCHAR2(4000),
v2 VARCHAR2(4000)
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
BADFILE ext_tab_dir:'bad.bad'
LOGFILE ext_tab_dir:'log.log'
FIELDS TERMINATED BY ','
)
LOCATION ('testfile.csv')
);
-- INSERT INTO tablename(v1,v2)
SELECT * From emp_load
and then getting next errors:
ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error error opening file C:/mydir/log.log
I do get that it has to do something with permissions, but I'm the one who created that directory, so how do I grant priveleges to myself if it is set like this by default? Is there any way to perform that sort of operation from PL/SQL?
Try something like this.
GRANT SELECT, INSERT, UPDATE, DELETE ON emp_load TO NikitaBuriak;
Replace 'NikitaBuriak' with the ID you used when you created the table..
You should grant all the privileges to the directories and files in the location pointing to the file you are trying to access.
eg : if the file you are trying to excess is in /home/dummy_folder/new_folder/file.txt
then you should grant all the administrative privileges to dummy_folder, new folder and file.txt as well

Insert into table with xmltype column from a xml file

Following is my query to insert xml file
INSERT INTO sampletagtable VALUES ( 1 , XMLType(bfilename('xmldir3', 'book.xml') , nls_charset_id('AL32UTF8') ));
Before that I have created the xmldir3 by the following query,
CREATE OR REPLACE DIRECTORY xmldir3 AS '/opt/user/nishanth/xmldir';
Here /opt/user/nishanth is a directory in my linux os.
book.xml is inside that specified directory.
I am getting the following error,
SQL Error: ORA-22285: non-existent directory or file for FILEOPEN operation
ORA-06512: at "SYS.XMLTYPE", line 296
ORA-06512: at line 1
22285. 00000 - "non-existent directory or file for %s operation"
*Cause: Attempted to access a directory that does not exist, or attempted
to access a file in a directory that does not exist.
*Action: Ensure that a system object corresponding to the specified
directory exists in the database dictionary, or
make sure the name is correct.
You created the directory as xmldir3, which is an unquoted identifier so it'll be upper-case in the data dictionary. But then you refer to it in lower-case. You need to use:
bfilename('XMLDIR3', 'book.xml')
You can check the actual directory name by querying the all_directories view:
SQL> CREATE OR REPLACE DIRECTORY xmldir3 AS '/opt/user/nishanth/xmldir';
Directory created.
SQL> SELECT directory_name, directory_path FROM all_directories;
DIRECTORY_NAME DIRECTORY_PATH
------------------------------ ----------------------------------------
XMLDIR3 /opt/user/nishanth/xmldir
...

Oracle external table with dba's directory

I wanted to create an external table, but did not have the CREATE ANY DIRECTORY permission (and could not have it granted). Fair enough, I asked the DBAs to run the following:
CREATE OR REPLACE DIRECTORY ext_data_files AS '/data/ext_data_files';
GRANT ALL ON DIRECTORY ext_data_files TO MYAPPUSER;
They did, and the final object has the following script:
CREATE OR REPLACE DIRECTORY
EXT_DATA_FILES AS
'/data/ext_data_files';
GRANT READ, WRITE ON DIRECTORY SYS.EXT_DATA_FILES TO MYAPPUSER;
(I got that from asking a desc with Toad)
I was then hoping to use this directory to create my external table with the script as follows:
CREATE TABLE MYAPPUSER.MY_EXT_TABLE
(
ID VARCHAR2(100 BYTE),
LOGIN VARCHAR2(100 BYTE),
CODE VARCHAR2(100 BYTE),
CREATED_AT VARCHAR2(100 BYTE)
)
ORGANIZATION EXTERNAL
( TYPE ORACLE_LOADER
DEFAULT DIRECTORY SYS.EXT_DATA_FILES
ACCESS PARAMETERS
( RECORDS DELIMITED BY NEWLINE
NOBADFILE
NOLOGFILE
FIELDS TERMINATED BY ';'
MISSING FIELD VALUES ARE NULL
( ID, LOGIN, CODE, CREATED_AT) )
LOCATION (SYS.EXT_DATA_FILES:'the_external_file.txt')
)
REJECT LIMIT 0
PARALLEL ( DEGREE DEFAULT INSTANCES DEFAULT )
NOMONITORING;
but then when I SELECT * FROM MY_EXT_TABLE, the result is the infamous
ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-04040: file the_external_file.txt in EXT_DATA_FILES not found
ORA-06512: at "SYS.ORACLE_LOADER", line 19
(which has quite a few hits on google, but none seem related)
I'm confident of the syntax since this is the exact same script used in our DEV environment. Also, the permissions of all files and directories involved were checked and there is nothing lower than 775.
The only difference I have here from DEV (where it works) is that the directory EXT_DATA_FILES was not created by MYAPPUSER. I tried to create a synonym for it.. but had no effect.
Maybe worth mentioning, it is Oracle 10g we are talking about.
Am I missing something obvious? Is this allowed?
All directories are in fact owned by SYS. That's why there is no CREATE DIRECTORY privilege, only CREATE ANY DIRECTORY.
So try the command without prefixing the directory name with the SYS schema and see what happens.
The error message reads:
"file the_external_file.txt in EXT_DATA_FILES not found"
Are you sure it's there?

Resources