Getting the timestamp of a file using PL/SQL - oracle

I am trying to get the timestamp of a text file abc.txt in some directory XYZ in oracle server. This file can get updated at any time in the day and i have to check if the file was updated any time after yesterday midnight, if yes i need to email that file as an attachment.
Is there any other way i can check this?
I have searched a lot over internet but could not find the solution.
Seriously not getting a clue of how to get it done.
It would be great if anyone could guide me.
Thanks.

I think you will have to do this by writing a java procedure, as described here by Tom Kyte:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:439619916584
GRANT JAVAUSERPRIV to <your user>
/
create global temporary table DIR_LIST
( filename varchar2(255) )
on commit delete rows
/
create or replace and compile java source named "DirList"
as
import java.io.*;
import java.sql.*;
public class DirList
{
public static void getList(String directory)
throws SQLException
{
File path = new File( directory );
String[] list = path.list();
String element;
for(int i = 0; i < list.length; i++)
{
element = list[i];
#sql { INSERT INTO DIR_LIST (FILENAME)
VALUES (:element) };
}
}
}
/
create or replace procedure get_dir_list( p_directory in varchar2 )
as language java
name 'DirList.getList( java.lang.String )';
/

Another approach might be to make use of the preprocessor directive for external tables.
Please have a look at Mr. Kyte's article in Nov/Dec 2012 Oracle Magazine. He is playing with unix df, you can play with unix ls or windows dir.
http://www.oracle.com/technetwork/issue-archive/2012/12-nov/o62asktom-1867739.html
SQL> create table df
2 (
3 fsname varchar2(100),
4 blocks number,
5 used number,
6 avail number,
7 capacity varchar2(10),
8 mount varchar2(100)
9 )
10 organization external
11 (
12 type oracle_loader
13 default directory exec_dir
14 access parameters
15 (
16 records delimited
17 by newline
18 preprocessor
19 exec_dir:'run_df.sh'
20 skip 1
21 fields terminated by
22 whitespace ldrtrim
23 )
24 location
25 (
26 exec_dir:'run_df.sh'
27 )
28 )
29 /
Table created.

Related

PL/SQL MERGE INTO statement ignored

I want to create procedure will move the product (isdiscontinued=1) to another table (Product_discontinued_[NTID]). Structure of the two tables is identical.
PROCEDURE move_table AS
begin
merge into PRODUCTS_DISCONTINUTED b
using PRODUCTS a
on (a.ID = b.ID)
when matched then
update set b.id = a.id,b.productname = a.productname,b.supplierid=a.supplierid,b.unitprice=a.unitprice,
b.package=a.package, b.isdiscontinuted=a.isdiscontinuted
where a.isdiscontinuted = 1
when not matched then
insert (id,productname,supplierid,unitprice,package,isdiscontinuted)
values( a.id,a.productname,a.supplierid,a.unitprice,a.package,a.isdiscontinuted)
where a.isdiscontinuted = 1; END move_table;
I tried to write a procedure to move table PRODUCTS_DISCONTINUTED to PRODUCTS with using MERGE INO statement but it always keep getting the following errors. Could you please help me. Much appreciated.
[enter image description here][2]
error
Terminate merge and remove null;
when not matched then
insert ...
where a.isdicontinuted = 1; --> semi-colon here
-- null; --> remove this
end move_table;
I created tables involved, simply by looking at code you posted. Doing so, procedure gets created:
SQL> CREATE OR REPLACE PROCEDURE move_table
2 AS
3 BEGIN
4 MERGE INTO PRODUCTS_DISCONTINUTED b
5 USING PRODUCTS a
6 ON (a.ID = b.ID)
7 WHEN MATCHED
8 THEN
9 UPDATE SET b.id = a.id,
10 b.productname = a.productname,
11 b.supplierid = a.supplierid,
12 b.unitprice = a.unitprice,
13 b.package = a.package,
14 b.isdiscontinuted = a.isdiscontinuted
15 WHERE a.isdiscontinuted = 1
16 WHEN NOT MATCHED
17 THEN
18 INSERT (id,
19 productname,
20 supplierid,
21 unitprice,
22 package,
23 isdiscontinuted)
24 VALUES (a.id,
25 a.productname,
26 a.supplierid,
27 a.unitprice,
28 a.package,
29 a.isdiscontinuted)
30 WHERE a.isdiscontinuted = 1;
31 END move_table;
32 /
Procedure created.
SQL>
However, error you specified:
ORA-00904: "ISDISCONTINUTED" invalid identifier
means that there's no column whose name is ISDISCONTINUTED. Are you sure you didn't make a typo? Compare table description to code in the procedure - I guess there's a mismatch.

ORA-12899: value too large for column - on export/import, both BYTE semantics, not CHAR

I have an Oracle DB on one Windows machine and perform an export of all tables + contents using SQL developer 4.0.2.15. File format is plain text SQL, ANSI ISO-8859-1. The line endings are done in UNIX style (1 byte).
The table / column definitions are like:
"PRODUCTNAME" VARCHAR2(120 BYTE),
When I execute this .sql file on the target Windows machine, tables are created and inserts are done. But some items that have exactly 120 bytes in the PRODUCTNAME (including 1 line feed character) fail to insert on the target machine.
I get:
ORA-12899: value too large for column "DBNAME"."TABLENAME"."PRODUCTNAME" (actual: 121, maximum: 120)
I don't understand why. I have no 2-byte characters in this particular string, and the export is definitely done using 0x0A as line break character (checked via Notepad++ status line and its HexView Plugin). I use drag&drop to open the .sql file in the target machine's SQL developer (same version). When I copy the productname with its line break into Notepad++ via clipboard, it count's 120 bytes of length.
I do not understand, why in Oracle developer the script counts this 1 extra character.
I have searched for this in google and found topics here on SO among others, but they don't help me or I don't fully understand them.
What do I miss? Please help!
Create a temporary table (say, TEST) having PRODUCTNAME VARCHAR2(200). Import data into it. Check rows that exceed length of 120 characters.
You might need to use the DUMP function, such as
select dump(productname) from test
It'll show you actual length of data stored in that column. Just for example:
SQL> select ename, dump(ename) dump_e from emp where rownum = 1;
ENAME DUMP_E
---------- ----------------------------------------
KING Typ=1 Len=4: 75,73,78,71
-----
this!
SQL>
[EDIT: TRIM example]
SQL> with test (id, col) as
2 (select 1, 'abc' from dual union
3 select 2, 'def ' from dual union
4 select 3, ' ghi ' from dual
5 )
6 select '#' || col || '#' col,
7 '#' || trim(col) || '#' new_col
8 from test
9 order by id;
COL NEW_COL
-------- --------
#abc# #abc#
#def # #def#
# ghi # #ghi#
SQL>

Strange Oracle XMLType.getClobVal() result

I use Oracle 11g (on Red Hat). I have simple regular table with XMLType column:
CREATE TABLE PROJECTS
(
PROJECT_ID NUMBER(*, 0) NOT NULL,
PROJECT SYS.XMLTYPE,
);
Using Oracle SQL Developer (on Windows) I do:
select T1.PROJECT P1 from PROJECTS T1 where PROJECT_ID = '161';
It works. I get one cell. I can double click and download whole XML file.
Then I tried to get result as CLOB:
select T1.PROJECT.getClobVal() P1 from PROJECTS T1 where PROJECT_ID = '161';
It works. I get one cell. I can double click and see whole text and copy it. BUT there is a problem. When I copy it to clipboard I get only first 4000 characters. It seems that there is 0x00 character at position 4000 and the rest of CLOB is not copied.
To confirm this, I wrote check in java:
// ... create projectsStatement
Reader reader = projectsStatement.getResultSet().getCharacterStream( "P1" );
BufferedReader bf = new BufferedReader( reader );
char buffer[] = new char[ 1024 ];
int count = 0;
int globalPos = 0;
while ( ( count = bf.read( buffer, 0, buffer.length ) ) > 0 )
for ( int i = 0; i < count; i++, globalPos++ )
if ( buffer[ i ] == 0 )
throw new Exception( "ZERO at " + Integer.toString(globalPos) );
Reader returns full XML but my exception is thrown because there is null character at position 4000. I could remove this single byte but this would be rather strange workaround.
I don't use VARCHAR2 there but maybe this problem is related to VARCHAR2 limitation (4000 bytes) somehow ? Any other ideas ? Is this an Oracle bug or am I missing something ?
-------------------- Edit --------------------
Value was inserted using following stored procedure:
create or replace
procedure addProject( projectId number, projectXml clob ) is
sqlstr varchar2(2000);
begin
sqlstr := 'insert into projects ( PROJECT_ID, PROJECT ) VALUES ( :projectId, :projectData )';
execute immediate sqlstr using projectId, XMLTYPE(projectXml);
end;
Java code used to call it:
try ( CallableStatement cs = connection.prepareCall("{call addProject(?,?)}") )
{
cs.setInt( "projectId", projectId );
cs.setCharacterStream( "projectXml", new StringReader(xmlStr) , xmlStr.length() );
cs.execute();
}
-------------------- Edit. SIMPLE TEST --------------------
I will use all I learned from your answers. Create simplest table:
create table T1 ( P XMLTYPE );
Prepare two CLOBs with XMLs. First with null character, second without.
declare
P1 clob;
P2 clob;
P3 clob;
begin
P1 := '<a>';
P2 := '<a>';
FOR i IN 1..1000 LOOP
P1 := P1 || '0123456789' || chr(0);
P2 := P2 || '0123456789';
END LOOP;
P1 := P1 || '</a>';
P2 := P2 || '</a>';
Check if null is in the first CLOB and not in the second one:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P1, chr(0) ) );
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P2, chr(0) ) );
We will get as expected:
14
0
Try to insert first CLOB into XMLTYPE. It will not work. It is not possible to insert such value:
insert into T1 ( P ) values ( XMLTYPE( P1 ) );
Try to insert second CLOB into XMLTYPE. It will work:
insert into T1 ( P ) values ( XMLTYPE( P2 ) );
Try to read inserted XML into third CLOB. It will work:
select T.P.getClobVal() into P3 from T1 T where rownum = 1;
Check if there is null. There is NO null:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P3, chr(0) ) );
It seams that there is no null inside database and as long as we are in the PL/SQL context, there is no null. But when I try to use following SQL in SQL Developer ( on Windows ) or in Java ( on Red Hat EE and Tomcat7 ) I get null character at position 4000 in all returned CLOBs:
select T.P.getClobVal() from T1 T;
BR,
JM
It's not an Oracle bug (it stores and retrieves the \0 just fine. It's a client/windows bug (Different clients behave differently in regards to "NUL" as does windows)
chr(0) is not a valid character in non-blobs really (I'm curious how you ever get the XMLType to accept it in the first place as usually it wouldn't parse).
\0 is used in C to denote the end of a string (NUL terminator) and some GUIs would stop processing the string at that point. For example:
![SQL> select 'IM VISIBLE'||chr(0)||'BUT IM INVISIBLE'
2 from dual
3 /
'IMVISIBLE'||CHR(0)||'BUTIM
---------------------------
IM VISIBLE BUT IM INVISIBLE
SQL>
yet toad fails miserably on this:
sql developer fares better, as you can see it:
but if you copy it, the clipboard will only copy it up to the nul character. this copy paste error isn't SQL developers fault though, it's a problem with windows clipboard not allowing NUL to paste properly.
you should just replace(T1.PROJECT.getClobVal(), chr(0), null) to get round this when using sql developer/windows clipboard.
I also was experiencing this same issue exactly as described by Mikosz (seeing an extra 'NUL' character around the 4000th character when outputting my XMLType value as a Clob). While playing around in SQLDeveloper I noticed an interesting workaround. I was trying to see the output of my XMLType, but was tired of scrolling to the 4000th character, so I started wrapping the Clob output in a substr(...). Much to my surprise, the issue actually disappeared. I incorporated this into my Java app and confirmed that the issue was no longer present and my Clob could be retrieved without the extra character. I know that this isn't an ideal workaround, and I'm still not sure why it works (would love if someone could explain it to me), but here's an abbreviated example of what I've currently got working:
// Gets the xml contents
String sql = "select substr(x.xml_content.getClobVal(), 0) as xml_content from my_table x";
ps = con.prepareStatement(sql);
if(rs.next()) {
Reader reader = new BufferedReader(rs.getCharacterStream("xml_content"));
...
}
Bug:14781609 XDB: XMLType.getclobval() returns a temporary LOB when XML is stored in a CLOB.
fix in patchset 11.2.0.4
and another solution
if read as blob, then no error like
T1.PROJECT.getBlobVal(nls_charset_id('UTF8'))
Easy enough to verify if it's the .getClobVal() call or not - perform an INSTR test in PL/SQL (not Java) on your resultant CLOB to see if the CHR(0) exists or not.
If it does not, then I would point the finger at your Oracle client install.

Copying data from LOB Column to Long Raw Column

I was looking for a query which picks data from a table having Blob column and update a table having LONG RAW column. It seems Oracle supports only up to 4000 characters. Is there a way to copy full data from blob to long raw.
I was using the follwing query
insert into APPDBA.QA_SOFTWARE_DUMMY
select SOFTWARE_ID, UPDATED_BY, CREATE_CHANGE_DATE, FILE_NAME,
DBMS_LOB.SUBSTR(SOFTWARE_FILE, 4000) SOFTWARE_FILE, SOFTWARE_TYPE
from APPDBA.QA_SOFTWARE_DUMMY_TEST ;
but DBMS_LOB.SUBSTR supports only upto 4000 characters.
Any help is highly appreciated.
PL/SQL will only read/write the first 32k of a LONG RAW and SQL will convert the column as a RAW so will only deal with the first 2000 bytes.
You can use java to access LONG RAW columns directly from the DB, as demonstrated in the question "Get the LENGTH of a LONG RAW".
Here's a little example, first the setup:
SQL> CREATE TABLE t (ID NUMBER PRIMARY key, source BLOB, destination LONG RAW);
Table created
SQL> DECLARE
2 l_lob BLOB;
3 BEGIN
4 INSERT INTO t VALUES (1, 'FF', '') RETURNING SOURCE INTO l_lob;
5 FOR i IN 1..10 LOOP
6 dbms_lob.writeappend(l_lob, 4000,
7 utl_raw.overlay('FF', 'FF', 1, 4000, 'FF'));
8 END LOOP;
9 END;
10 /
PL/SQL procedure successfully completed
The java class:
SQL> CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "Raw" AS
2 import java.io.*;
3 import java.sql.*;
4 import oracle.jdbc.driver.*;
5
6 public class Raw {
7
8 public static void updateRaw(int pk) throws SQLException,IOException {
9
10 Connection conn = new OracleDriver().defaultConnection();
11
12 PreparedStatement ps = conn.prepareStatement
13 ( "SELECT dbms_lob.getlength(source) length, source "
14 + "FROM t WHERE id = ? FOR UPDATE");
15 ps.setInt( 1, pk);
16 ResultSet rs = ps.executeQuery();
17
18 rs.next();
19 int len = rs.getInt(1);
20 InputStream source = rs.getBinaryStream(2);
21 byte[] destArray = new byte[len];
22 int byteRead = source.read(destArray);
23 ps = conn.prepareStatement(
24 "UPDATE t SET destination = ? WHERE id = ?");
25 ((OraclePreparedStatement) ps).setRAW(1,
26 new oracle.sql.RAW(destArray));
27 ps.setInt(2, pk);
28 ps.execute();
29 }
30 }
31 /
Java created
You can call this procedure from PL/SQL:
SQL> CREATE OR REPLACE
2 PROCEDURE update_raw(p_id NUMBER)
3 AS LANGUAGE JAVA NAME 'Raw.updateRaw(int)';
4 /
Procedure created
SQL> exec update_raw(1);
PL/SQL procedure successfully completed
Despite the fact that you make a reversal (normaly you should move from LONG to LOB, LONG being obsolete)...
You must use dbms_lob package, and make some plsql:
Eventualy you can use read, getlength...
Doc you can find here Psoug.org
or on Oracle doc

How can I get values from one table to another via similar values?

I have a table called excel that has 3 columns, name, id, and full_name. The name part is the only one I have and I need to fill id and full_name. The other table that contains the data is called tim_pismena and has 2 columns that I need, id and pismeno_name (the actual names are not important, but i'm writing them just for clarity). In pseudooracle code :) the select that gets me the values from the second table would be done something like this:
SELECT tp.id, tp.pismeno_name
FROM tim_pismena tp
WHERE upper(tp.pismeno_name) LIKE IN upper('%(SELECT name FROM excel)%')
and when used with an insert, the end result should be something like
name id full_name
Happy Joe 55 Very fun place Happy Joe, isn't it?
Use merge statement
1 MERGE
2 INTO excel tgt
3 USING tim_pismenae src
4 ON ( upper(src.naziv_pismena) LIKE '%'||upper(tgt.ime)||'%')
5 WHEN MATCHED
6 THEN
7 UPDATE
8 SET tgt.id = src.id
9 , tgt.full_name = src.naziv_pismena
10 WHEN NOT MATCHED
11 THEN
12 INSERT ( tgt.name
13 , tgt.id
14 , tgt.full_name )
15 VALUES ( src.naziv_pismena
16 , src.id
17 , src.naziv_pismena )
18 WHERE (1 <> 1);

Resources