I am trying to write an expression where it would give the below output in Abinitio GDE - expression

input in zero byte file made in unix:
2000560|Bibek|28
3490679|kjdsk|56
1775679|Samrat|45
my output needed is
Bi
kj
Sa

record
string("|") col1;
string("|") col2
string("\n") col3;
end;
out::transform(in) = begin
out.value::string_substring(in.col2, 1,2);
end;

read file then use reformat. Below is the transformation
out::reformat(in)=
begin
out.out_field:: string_substring(in.field2,0,2);
end;
index starts from 0

Related

My long time SQL*Plus loop doesn't print DBMS_OUTPUT.PUT_LINE output during execution

I know that in order to print something on sqlplus like below:
begin
dbms_output.put_line('Hello!');
end;
/
I need to call
set serveroutput on;
before that.
I also know that is not needed, but I can also call
DBMS_OUTPUT.enable;
before, just in case. This is working for me.
But what if I want to keep printing the progress of a long loop? It seems impossible to me. I've tried everything to print some progress on the loop below but just doesn't work. Is there some way of doing that? I even tried to spool to a file and didn't work.
Note 1: I can't truncate or partition this table as the DBA doesn't want to help me with that, so I have to use this nasty loop...
Note 2: I've noticed that once the loop is done, the whole output is printed. Looks like oracle is buffering the output and printing everything at the end. I'm not sure how to avoid that and print on every loop iteration.
set serveroutput on;
declare
e number;
i number;
nCount number;
f number;
begin
DBMS_OUTPUT.enable;
dbms_output.put_line('Hello!');
select count(*) into e from my_big_table where upd_dt < to_date(sysdate-64);
f :=trunc(e/10000)+1;
for i in 1..f
loop
delete from my_big_table where upd_dt < to_date(sysdate-64) and rownum<=10000;
commit;
DBMS_OUTPUT.PUT_LINE('Progress: ' || to_char(i) || ' out of ' || to_char(f));
end loop;
end;
Thank you for any answer.
There are 2 standard ways for such things:
set module and action in your session DBMS_APPLICATION_INFO.SET_MODULE:
SQL> exec DBMS_APPLICATION_INFO.SET_MODULE('my_long_process', '1 from 100');
PL/SQL procedure successfully completed.
SQL> select action from v$session where module='my_long_process';
ACTION
----------------------------------------------------------------
1 from 100
set session_longops:
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS
I'd recommend it in your case since that is exactly designed for long operations.
Example on Oracle-Base.
----
PS: dbms_output,put_line saves all output in a collection (nested table) variable of dbms_output package, so you can't get it from another session and client can't get it during user call (execution). In addition to set serveroutput on you can also get the output using dbms_output.get_lines: http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_output-without-serveroutput-on/
Btw, in case if you need to filter or analyze output from dbms_output, sometimes it's convenient to get output in a query, so you can use filter strings in where clause or aggregate them: https://gist.github.com/xtender/aa12b537d3884f4ba82eb37db1c93c25
DBMS_OUTPUT will only ever be displayed after the PL/SQL code has terminated and control has returned to the calling program.
Output is, as you found, buffered. When your PL/SQL code finishes, then the calling program (e.g. SQL*Plus) can go and fetch that output.
Insert into another table, maybe call it "MYOUTPUT".
Create the table:
create table myoutput (lineno number, outline varchar2(80));
Add this after your delete:
insert into MYOUTPUT values (i,'Progress: ' || to_char(i) || ' out of ' || to_char(f));
Then select from MYOUTPUT periodically to see progress.
select outline from myoutput order by lineno;
Bobby
You can use UTL_FILE to write output to an external file, as in:
DECLARE
fh UTL_FILE.FILE_TYPE;
nRow_count NUMBER := 0;
BEGIN
fh := UTL_FILE.FOPEN('DIRECTORY_NAME', 'some_file.txt', 'w');
FOR aRow IN (SELECT *
FROM SOME_TABLE)
LOOP
nRow_count := nRow_count + 1;
IF nRow_count MOD 1000 = 0 THEN
UTL_FILE.PUT_LINE(fh, 'Processing row ' || nRow_count);
UTL_FILE.FFLUSH(fh);
END IF;
-- Do something useful with the data in aRow
END LOOP; -- aRow
UTL_FILE.FCLOSE_ALL; -- Close all open file handles, including
-- the ones I've forgotten about...
END;

ROWNUM works only for one row. How to fetch rows after that?

I want to extract BLOB data and write a file (suggest it should be excel or txt or any other) out of it. A single cell has upto 60k characters. I wanted to write a script that reads whole table with BLOB data and write into a file. In below code ROWNUM works only for one row. what's the alternative? Or is there another script that can help me to achieve my ultimate objective to read BLOB and write file?
SET SERVEROUTPUT ON;
DECLARE
TotalRows NUMBER;
TotalChar NUMBER;
CharCounter NUMBER;
BEGIN
SELECT count(*) INTO TotalRows FROM <TableName>;
--dbms_output.Put_line(RC);
--END;
FOR RC IN 1..TotalRows
LOOP
-----------------Code for Rows starts--------------------------------------------------------------------------------
dbms_output.Put_line('Row '||RC||' Started.');
SELECT Length(<ColumnWithBLOBDataType>) INTO TotalChar FROM <TableName> where **Rownum = RC**;
dbms_output.Put_line('Crossed Char counting query. TotalChar='||TotalChar);
CharCounter:=TotalChar/2000+1;
dbms_output.Put_line('Loop will run these many times= '||CharCounter|| ' and Total Chars=' ||TotalChar);
For CC IN 1..CharCounter
LOOP
dbms_output.Put_line('Trip: '||CC);
END LOOP;
-----------------Code for Rows Ends----------------------------------------------------------------------------------------
TotalChar :=0;
dbms_output.Put_line('Row '|| RC||' Done. TotalChar='|| TotalChar);
END LOOP;
dbms_output.Put_line('Exited loop 1.');
END;
You normally don't use ROWNUM to select rows from a table. It's not safe and not necessary. Normally, you can do it with a single FOR SELECT loop:
DECLARE
CharCounter NUMBER;
part VARCHAR2(30000);
offset NUMBER;
BEGIN
FOR r IN (SELECT c,
rownum as rc,
dbms_lob.getlength(c) as totalchar
FROM mytable)
LOOP
-----------------Code for Rows starts--------------------------------------------------------------------------------
dbms_output.put_line('Row '||r.rc||' Started.');
dbms_output.put_line('Crossed Char counting query. TotalChar='||r.totalchar);
offset := 1;
WHILE (offset <= r.totalchar) LOOP
part := dbms_lob.substr(r.c, 20000, offset);
offset := offset + length(part);
dbms_output.put(part);
END LOOP;
dbms_output.put_line('');
END LOOP;
END;
/

insert rows in different order in oracle table

I am using ODI 12c so the mission is to insert one plat file into one table Oracle
the file is like :
H030201707761133020171085009CA0126357320150506141438SL xxxx xxx xxx
***DEB062
09001SD
1003020171085009
....
...
..
.
.
.
0000010000001389600000013896
509000002
199
***FIN062
I have one table 'A' which constitute one column 'COL' (lenght=250) where I want to save all my file's text (insert line by line). it save it but not like in my file order why !
it save it like
1003020171085009
xxxx
1003020171085009
....
...
..
***FIN062
.
H030201707761133020171085009CA0126357320150506141438SL xxxx xxx xxx
.
509000002
199
0000010000001389600000013896
Rows in a table in a relational database do not have an 'order'. Unless you supply an ORDER BY clause with your SELECT statement the database is free to return the rows however it chooses. I suggest you add another column to your table, perhaps called LINE_NUMBER, in which you might store a "line number" value that you could use to order the rows from the table as you wish.
Best of luck.
EDIT
If you really don't want to add a column to do the ordering of your data you can always embed a sequence number in the text of the COL column. For example, you could store the sequence number as the first 8 characters of the file, in a manner similar to the following:
DECLARE
nLine_number NUMBER;
strLine VARCHAR2(250);
f UTL_FILE.FILE_TYPE;
BEGIN
f := UTL_FILE.FOPEN('dir', 'file', 'r');
SELECT COUNT(*)
INTO nLine_number
FROM A;
BEGIN
WHILE TRUE THEN
UTL_FILE.GET_LINE(f, strLine, 242); -- 8 less than size of A.COL
-- Insert new line into A.COL
nLine_number := nLine_number + 1;
INSERT INTO A(COL)
VALUES (TO_CHAR(nLine_number, '00000000') || strLine);
LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
UTL_FILE.FCLOSE(f);
END;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
UTL_FILE.FCLOSE_ALL;
RAISE;
END;
Then when you want to read through A in the order the lines were added to the table you can do:
SELECT SUBSTR(COL, 9)
FROM A
ORDER BY TO_NUMBER(SUBSTR(COL, 1, 8);
Not pretty, but it avoids having to add a LINE_NUMBER column to A.
We found a solution .If you are using ODI you need only put nothing in INSERT_HINT input text .let it empty like in picture below...And it will save your lines as they are in the plat file

Error : ORA-01704: string literal too long

While I try to set the value of over 4000 characters on a field that has data type CLOB, it gives me this error :
ORA-01704: string literal too long.
Any suggestion, which data type would be applicable for me if I have to set value of unlimited characters although for my case, it happens to be of about 15000 chars.
Note : The long string that I am trying to store is encoded in ANSI.
What are you using when operate with CLOB?
In all events you can do it with PL/SQL
DECLARE
str varchar2(32767);
BEGIN
str := 'Very-very-...-very-very-very-very-very-very long string value';
update t1 set col1 = str;
END;
/
Proof link on SQLFiddle
Try to split the characters into multiple chunks like the query below and try:
Insert into table (clob_column) values ( to_clob( 'chunk 1' ) || to_clob( 'chunk 2' ) );
It worked for me.
To solve this issue on my side, I had to use a combo of what was already proposed there
DECLARE
chunk1 CLOB; chunk2 CLOB; chunk3 CLOB;
BEGIN
chunk1 := 'very long literal part 1';
chunk2 := 'very long literal part 2';
chunk3 := 'very long literal part 3';
INSERT INTO table (MY_CLOB)
SELECT ( chunk1 || chunk2 || chunk3 ) FROM dual;
END;
Hope this helps.
The split work until 4000 chars depending on the characters that you are inserting. If you are inserting special characters it can fail.
The only secure way is to declare a variable.
Though its a very old question but i think sharing experience still might help others:
Large text can be saved in a single query if we break-down it in chunks of 4000 bytes/characters by concatinating them using '||'
Running following query will tell you:
Required Number of chunks containing 4000 bytes
Remaining bytes
Since, in given example you are trying to save text contining 15000 bytes (characters), so,
select 15000/4000 chunk,mod(15000,4000) remaining_bytes from dual;
Result:
That means, you need to concatenate 3 chunks of 4000 bytes and one chunk of 3000 bytes, so it would be like:
INSERT INTO <YOUR_TABLE>
VALUES (TO_CLOB('<1st_4K_bytes>') ||
TO_CLOB('<2nd_4K_bytes>') ||
TO_CLOB('<3rd_4K_bytes>') ||
TO_CLOB('<last_3K_bytes>)');
create a function that return a clob
create function ret_long_chars return clob is
begin
return to_clob('put here long characters');
end;
update table set column = ret_long_chars;
INSERT INTO table(clob_column) SELECT TO_CLOB(q'[chunk1]') || TO_CLOB(q'[chunk2]') ||
TO_CLOB(q'[chunk3]') || TO_CLOB(q'[chunk4]') FROM DUAL;
Accepted answer did not work for me in sql developper but combination of this answer and another one did :
DECLARE
str varchar2(32767);
BEGIN
update table set column = to_clob('Very-very-...-very-very-very-very-very-very long string value');
END;
/

PL/SQL - String concatenation algorithm

I'm working on a PL/SQL algorithm, with Oracle.
I currently have a procedure which have one single numeric parameter. My procedure have to create a string which contains as much '0' as the parameter value.
I am currently using a for loop to achieve this:
MY_STRING VARCHAR2(30);
FOR I IN 1..MY_PARAMETER
LOOP
MY_STRING := CONCAT(MY_STRING, '0');
END LOOP;
Is it possible to do it in a linear way ? I mean without a loop, or even with one single statement.
Any help would be appreciated !
Thanks.
You can use LPAD() to achieve this:
SELECT LPAD('0', my_parameter, '0')
FROM DUAL
Here is the link to the manual:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions082.htm#i1371196
Demonstration of accepted answer using various input values.
set serveroutput on size 1000000 format wrapped
Declare
my_parameter Number(3);
my_string Varchar2(10);
Begin
DBMS_Output.Put_Line('Input Output');
DBMS_Output.Put_Line('===== ======');
For vLoopVar IN 0..5 Loop
my_parameter := vLoopVar;
If (vLoopVar = 5) Then
my_parameter := '';
End If;
DBMS_Output.Put(RPAD('~' || my_parameter || '~',6));
--Method 1
my_string := lpad('0',my_parameter,'0');
DBMS_Output.Put_Line('~' || my_string || '~');
End Loop;
End;
/
Output
Input Output
===== ======
~0~ ~~
~1~ ~0~
~2~ ~00~
~3~ ~000~
~4~ ~0000~
~~ ~~

Resources