Parsing a multi line flat file in Oracle - sql

How do i parse a multi line file using UTL_FILE? In the below example snippet -
The line starting with '1' is the File header - one per file.
The line starting with '5' is the transaction header - one per transaction
The line starting with '8' is the transaction trailer - one per transaction
The line starting with '9' is the file footer - one per file.
I need logic to 1) read the file lines and 2) to be able to distinguish where a transaction starts and ends. Per line, I know Oracle has the instr and substr to distinguish different values in it.
Any suggestions would be welcome! Thanks for your time.
1TreasuryPart 201610031830MEMO
53336 Bank1Base0000001
650 3100000126 1-30-00010-00 000002126100000000000000021261USD20161003RAYMOND SOLIS jane.doe#gmail.com 205-888-9900 20161003020030000001 WEBENRAPC34560000000000 WEB
800000000010000000212610000000000000000001
53336 Bank1Base0000002
800000000000000000000000000000000000000002
53343 ToddMUD 0000001
800000000000000000000000000000000000000001
53343 ToddMUD 0000002
800000000000000000000000000000000000000002
53351 DenisTM 0000001
650 3100000128 7779026 000004000000000000000000080000USD20161003Denis Pellerin jack.doe#gmail.com 405-922-2116 20161003100421000001 WEBUNEAPC34560000000000 WEB
650 3100000128 7779026 000004000000000000000000080000USD20161003Denis Pellerin jack.doe#gmail.com 405-922-2116 20161003100421000002 WEBUNEAPC34560000000000 WEB
800000000020000000800000000000000000000001
53351 DenisTM 0000002
800000000000000000000000000000000000000002
9000006000000000003000000101261000000000000

I'm not quite sure what you're looking for. Posting code is always helpful so that we're not guessing. I'd think that you'd want something like this where there are separate procedures defined to parse each individual type of line.
declare
l_file utl_file.file_type;
l_line varchar2(4000);
l_in_transaction boolean := false;
begin
l_file := utl_file.fopen( <<parameters>> );
loop
utl_file.get_line(l_file, l_line);
if( substr(l_line,1,1) = '1' and l_in_transaction = false)
then
parse_file_header( l_line );
end if;
if( substr(l_line,1,1) = '5' and l_in_transaction = false )
then
parse_transaction_header( l_line );
l_in_transaction := true;
end if;
if( l_in_transaction = true)
then
parse_transaction_row( l_line );
end if;
if( substr(l_line,1,1) = '8' and l_in_transaction = true)
then
parse_transaction_trailer( l_line );
l_in_transaction := false;
end if;
if( substr(l_line,1,1) = '9' and l_in_transaction = false)
then
parse_file_trailer( l_line );
end if;
end loop;
exception
when no_data_found
then
utl_file.fclose( l_file );
end;

Related

ORACLE SQL function to return JSON response

I have table like below. I am trying to pull all BRKPK_CNTNR_ID, SSP_Q with respect to each OVRPK_CNTNR_ID
enter image description here
Below query runs fine and produces desired result.
DECLARE
json_objects JSON_OBJECT_LIST := JSON_OBJECT_LIST() ;
counter NUMBER := 1;
BEGIN
FOR ovrpk_detail IN (SELECT OVRPK_CNTNR_ID ,BRKPK_CNTNR_ID,ITEM_DISTB_Q FROM OVRPK_DET od WHERE od.OVRPK_CNTNR_ID='92000000356873110552') LOOP
begin
json_objects.extend;
json_objects(counter) :=JSON_UTIL.JSON_OBJECT(
JSON_ATTRIBUTE_LIST(
JSON_UTIL.JSON_ATTRIBUTE('over_pack_container_id',ovrpk_detail.OVRPK_CNTNR_ID),
JSON_UTIL.JSON_ATTRIBUTE('break_pack_container_id',ovrpk_detail.BRKPK_CNTNR_ID),
JSON_UTIL.JSON_ATTRIBUTE('item_distributed_quantity',ovrpk_detail.ITEM_DISTB_Q)
));
counter := counter+1;
END;
END LOOP;
dbms_output.put_line( JSON_UTIL.JSON_ARRAY(json_objects));
END;
I am expecting is to create function that takes OVRPK_CNTNR_ID as input and returns JSON_OBJECT_LIST as output.
Here is my query I tried.
CREATE OR REPLACE FUNCTION get_json_objects(ovrk_cntnr_id IN CHAR)
RETURN JSON_OBJECT_LIST IS
json_objects JSON_OBJECT_LIST := JSON_OBJECT_LIST();
BEGIN
DECLARE counter NUMBER := 1;
FOR ovrpk_detail IN (SELECT OVRPK_CNTNR_ID ,BRKPK_CNTNR_ID FROM OVRPK_DET od WHERE od.OVRPK_CNTNR_ID= ovrk_cntnr_id) LOOP
begin
json_objects.extend;
json_objects(counter) :=JSON_UTIL.JSON_OBJECT(
JSON_ATTRIBUTE_LIST(
JSON_UTIL.JSON_ATTRIBUTE('over_pack_container_id',ovrpk_detail.OVRPK_CNTNR_ID),
JSON_UTIL.JSON_ATTRIBUTE('break_pack_container_id',ovrpk_detail.BRKPK_CNTNR_ID)
));
counter := counter+1;
END;
END LOOP;
RETURN json_objects;
END;
DECLARE
json_return_object JSON_OBJECT_LIST;
ovrk_cnt_i char := '92000000356873110552'
BEGIN
json_return_object := get_json_objects(ovrk_cnt_i);
dbms_output.put_line('JSON Object is: ' || json_return_object);
END;
I am missing something, would anyone help me to resolve this issue? Thank you
Note: I am using Oracle 12.c database which does not support JSON however, JSON_UTIL is library written internally to address same
We do not have your packages or functions so this is difficult to test.
Your code has a DECLARE without a corresponding BEGIN or END. If you get rid of all the unnecessary DECLARE/BEGIN/END statements then you can simplify it to:
CREATE OR REPLACE FUNCTION get_json_objects(
ovrk_cntnr_id IN CHAR
)
RETURN JSON_OBJECT_LIST
IS
json_objects JSON_OBJECT_LIST := JSON_OBJECT_LIST();
counter NUMBER := 1;
BEGIN
FOR ovrpk_detail IN (
SELECT OVRPK_CNTNR_ID,
BRKPK_CNTNR_ID
FROM OVRPK_DET
WHERE OVRPK_CNTNR_ID = ovrk_cntnr_id
) LOOP
json_objects.extend;
json_objects(counter) :=JSON_UTIL.JSON_OBJECT(
JSON_ATTRIBUTE_LIST(
JSON_UTIL.JSON_ATTRIBUTE('over_pack_container_id',ovrpk_detail.OVRPK_CNTNR_ID),
JSON_UTIL.JSON_ATTRIBUTE('break_pack_container_id',ovrpk_detail.BRKPK_CNTNR_ID)
)
);
counter := counter+1;
END LOOP;
RETURN json_objects;
END;
/
If your package functions are callable from SQL then you should be able to simplify it further to:
CREATE OR REPLACE FUNCTION get_json_objects(
i_ovrpk_cntnr_id IN OVRPK_DET.OVRPK_CNTNR_ID%TYPE
) RETURN JSON_OBJECT_LIST
IS
json_objects JSON_OBJECT_LIST;
BEGIN
SELECT JSON_UTIL.JSON_OBJECT(
JSON_ATTRIBUTE_LIST(
JSON_UTIL.JSON_ATTRIBUTE('over_pack_container_id', OVRPK_CNTNR_ID),
JSON_UTIL.JSON_ATTRIBUTE('break_pack_container_id', BRKPK_CNTNR_ID)
)
)
BULK COLLECT INTO json_objects
FROM OVRPK_DET
WHERE OVRPK_CNTNR_ID = i_ovrpk_cntnr_id;
RETURN json_objects;
END;
/
DECLARE
json_return_object JSON_OBJECT_LIST;
ovrk_cnt_i OVRPK_DET.OVRPK_CNTNR_ID%TYPE := '92000000356873110552'
BEGIN
json_return_object := get_json_objects(ovrk_cnt_i);
dbms_output.put_line('JSON Object is: ' || json_return_object);
END;
/

csv file is not updating while saving data from TwinCat

I have created a plc program in TwinCat and its saving data into csv file. But variable values are not updating. Only one value is repeating in csv file again and and again. Where I am doing wrong !!! Here is my code:
PROGRAM MAIN
VAR
// Open, close and write function block
fbFileOpen: FB_FileOpen;
fbFileClose: FB_FileClose;
fbFileWrite: FB_FileWrite;
fbFormatString2: FB_FormatString2;
fbGetTime: NT_GetTime;
//file variables
nState : INT := 0;
nCounter : LREAL :=0;
hFile: UINT;
sPathName : T_MaxString;
sWriteBuffer : STRING(5000);
sBufferTemp : STRING(1000);
bBufferTemp : BOOL;
sFormat : STRING(255);
//General Variables
bFill: BOOL;
bWrite: BOOL;
rTimestamp : LREAL;
rCurrent: LREAL;
rActPos: LREAL;
nTimeMilli: INT;
i: ULINT;
END_VAR
// Input values
//------------------------------------------------------------------------------------------------------------------------
rTimestamp:= ULINT_TO_LREAL(F_GetSystemTime());
nCounter:= nCounter+1;
rCurrent:= (nCounter+1)/100;
rActPos:= (nCounter+1)/200;
IF bFill THEN
FOR i :=0 TO 10000000 BY 1 DO
GVL.arrLog[i].rTimestamp := rTimestamp;
GVL.arrLog[i].rCurrent := rCurrent;
GVL.arrLog[i].rActPos := rActPos;
END_FOR
END_IF
// Function Block for Current Date and Time
//------------------------------------------------------------------------------------------------------------------------
IF fbGetTime.START AND NOT fbGetTime.BUSY THEN // simple flip flop for quick update of time
fbGetTime.START := FALSE;
ELSE
fbGetTime.START := TRUE;
END_IF
fbGetTime(
NETID:= ,
START:= ,
TMOUT:= ,
BUSY=> ,
ERR=> ,
ERRID=> ,
TIMESTR=> ); // The TIMESTR is used to get times and dates
//Case Statements that will handle sequence of writing
//------------------------------------------------------------------------------------------------------------------------
CASE nState OF
0: //Wait for write trigger
IF bWrite THEN
nState := 10;
bWrite := FALSE;
END_IF
10: //Create file path and file using date
sPathName := CONCAT('D:\Data\', WORD_TO_STRING(fbGetTime.TIMESTR.wYear));
sPathName := CONCAT(sPathName,'_');
sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wMonth));
sPathName := CONCAT(sPathName,'_');
sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wDay));
sPathName := CONCAT(sPathName,'_');
sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wHour));
sPathName := CONCAT(sPathName,'_');
sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wMinute));
sPathName := CONCAT(sPathName,'_Datalog.csv');
nState:= 20;
fbFileOpen.bExecute := TRUE;
20: //Open and wait for file to open
fbFileOpen.bExecute := TRUE;
IF NOT fbFileOpen.bBusy AND NOT fbFileOpen.bError THEN
fbFileOpen.bExecute := FALSE;
nState := 30;
END_IF
30: // Write contents in file
sWriteBuffer := 'Name, fCurrentScaled, fActPos $n';
sFormat := '%F, %F, %F $n';
nTimeMilli := WORD_TO_INT(fbGetTime.TIMESTR.wMilliseconds);
IF WORD_TO_STRING(fbGetTime.TIMESTR.wMinute) <> INT_TO_STRING(40) THEN
FOR nTimeMilli:= 0 TO 999 BY 1 DO
fbFormatString2(
pFormatString:= ADR(sFormat),
arg1:= F_LREAL(GVL.arrLog[i].rTimestamp),
arg2:= F_LREAL(GVL.arrLog[i].rCurrent),
arg3:= F_LREAL(GVL.arrLog[i].rActPos),
pDstString:= ADR(sWriteBuffer),
nDstSize:= SIZEOF(sWriteBuffer),
bError=> ,
nErrId=> );
bBufferTemp := CONCAT2(pSrcString1 := ADR(sWriteBuffer),
pSrcString2 := ADR(sBufferTemp),
pDstString:= ADR(sWriteBuffer),
nDstSize := SIZEOF(sWriteBuffer));
END_FOR
ELSE
nState := 40;
fbFileWrite.bExecute := TRUE;
END_IF
40: // Write data in file and Wait for writing in the file
fbFileWrite.bExecute := TRUE;
IF NOT fbFileWrite.bBusy AND NOT fbFileWrite.bError THEN
fbFileWrite.bExecute := FALSE;
nState := 50;
fbFileClose.bExecute := TRUE;
END_IF
50: // close file and wait for it to close
fbFileClose.bExecute := TRUE;
IF NOT fbFileClose.bBusy AND NOT fbFileClose.bError THEN
fbFileClose.bExecute := FALSE;
nState:= 0;
END_IF
END_CASE
// FunctionBlocks for OPEN, WRITE and CLOSE
//------------------------------------------------------------------------------------------------------------------------
fbFileOpen(
sNetId:= '', //The netID does not need to be specified for local system
sPathName:= sPathName,
nMode:= FOPEN_MODEAPPEND OR FOPEN_MODEPLUS, // Open empty file for both read and write. If file exists then its content are destroyed
ePath:= PATH_GENERIC,
bExecute:= ,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
hFile=> hFile); // This file handle will be same for all function blocks.
fbFileClose(
sNetId:= '',
hFile:= hFile,
bExecute:= ,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
fbFileWrite(
sNetId:= '',
hFile:= hFile,
pWriteBuff:= ADR(sWriteBuffer), // A pointer is used to get address
cbWriteLen:= SIZEOF(sWriteBuffer), // Needs to know to size of string going to be written
bExecute:= ,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
cbWrite=> );
I have created a counter and divided into smaller portion so that I get several values for one second. Is there update syntax I am missing?
The problem would appear to be in your step 30. It looks like you're trying to execute the file write during the 40th minute of the hour, and the rest of the time you're assembling the string to be written. But you have the line sWriteBuffer := 'Name, fCurrentScaled, fActPos $n'; at the beginning of step 30, outside of the conditional block, so it will execute every time.
When the 40th minute occurs and you move to the next step to do the file write, you're still executing that line which will overwrite whatever was put into sWriteBuffer by fbFormatString2. I think the assignment statements for sWriteBuffer and sFormat should be inside the IF statement.
Also, I don't know why you have the line nTimeMilli := WORD_TO_INT(fbGetTime.TIMESTR.wMilliseconds); when you're using nTimeMilli as the index variable in your FOR loop. Is that supposed to be i?
You don't show how bWrite is activated, which starts the state machine, but what if it happened to be triggered right on the 40th minute? Your step 30 would go immediately into the file write without assembling the values to be written.

extract BLOB from Oracle

I would like to export data from my database locally, the column that contains the blob is "bbl_fic".
Is it possible to export my data without creating a package? With just one SQL request?
I can't use C# or Java to extract the data, and I don't really know how to do it.
thx!
One choice is to use SQLcl ( http://www.oracle.com/technetwork/developer-tools/sqlcl/overview/index.html)
This tool is written in java and can use things like the nashorn/javascript engine for local scripting. This snippet will perform a select of 3 columns. ID just the table PK , name the name of the file to create, and content the BLOB to extract from the db.
The script command triggers this scripting. I placed this code below into a file named blob2file.sql
All this adds up to zero plsql, zero directories instead just some sql scripts with javascript mixed in.
script
// issue the sql
var binds = {}
var ret = util.executeReturnList('select id,name,content from images',binds);
// loop the results
for (i = 0; i < ret.length; i++) {
// debug is nice
ctx.write( ret[i].ID + "\t" + ret[i].NAME+ "\n");
// get the blob stream
var blobStream = ret[i].CONTENT.getBinaryStream(1);
// get the path/file handle to write to
var path = java.nio.file.FileSystems.getDefault().getPath(ret[i].NAME);
// dump the file stream to the file
java.nio.file.Files.copy(blobStream,path);
}
/
The result is my table emptied into files ( I only had 1 row )
SQL> #blob2file.sql
1 eclipse.png
blob2file.sql eclipse.png
SQL>
Create a directory the database can use to export the data:
CREATE DIRECTORY export_dir AS '/path/to/your/directory';
Then use a PL/SQL script to export all the BLOBs to that directory:
DECLARE
v_start NUMBER(38,0);
v_size CONSTANT NUMBER( 5,0) := 32000;
v_len NUMBER(38,0);
v_buffer RAW(32000);
v_file UTL_FILE.FILE_TYPE;
BEGIN
FOR r IN ( SELECT filename, bbl_fic FROM your_table )
LOOP
v_file := UTL_FILE.FOPEN('EXPORT_DIR', r.filename, 'wb', 32760 );
v_start := 1;
v_len := DBMS_LOB.GETLENGTH( r.bbl_fic );
WHILE v_start <= v_len LOOP
DBMS_LOB.READ(
r.bbl_fic,
LEAST( v_len - v_start + 1, v_size ),
v_start,
v_buffer
);
UTL_FILE.PUT_RAW( v_file, v_buffer );
UTL_FILE.FFLUSH( v_file );
v_start := v_start + v_size;
END LOOP;
UTL_FILE.FCLOSE( v_file );
END LOOP;
END;
/

Sending CLOB data of length 32000 in utl_http.req throws ORA:06052 POST method

I am trying to send an XML as a URL parameter from PL/SQL.
But when I try to send it the error "ORA:06052" occurs. Below is the PL/SQL code
CREATE OR REPLACE FUNCTION EMASDB.ESIGN(TY IN VARCHAR2,DATA1 IN CLOB,DATA2 IN CLOB) RETURN clob
IS
XML CLOB;
v_data_post CLOB;
resp utl_http.resp;
req utl_http.req;
v_txt CLOB;
BEGIN
IF TY='REGISTER' THEN
XML:='<register><uniqueid>'||DATA2||'</uniqueid><DATA1>'||DATA1||'</DATA1><userEnable>true</userEnable><originalContent>'||DATA2||'</originalContent></register>';
ELSIF TY='AUTHENTICATE' THEN
XML :='<AuthenticateDet><uniqueId>'||DATA2||'</uniqueId><DATA1>'||DATA1||'</DATA1><originalContent>'||DATA2||'</originalContent><referenceNo></referenceNo></AuthenticateDet>';
ELSE
XML :='<verifyDet><dataType>pkcs7</dataType><DATA1>'||DATA1||'</DATA1><originalContent>'||DATA2||'</originalContent><responseFormat>plain</responseFormat></verifyDet>';
DBMS_OUTPUT.PUT_LINE('A');
END IF;
req := UTL_HTTP.begin_request ('url','POST','HTTP/1.1');
utl_http.set_header(req, 'Content-Type', 'application/x-www-form-urlencoded');
utl_http.set_header(req, 'Content-Length', length(XML));
v_data_post :='xml='||XML;
/*utl_http.write_text(req, v_data_post);
resp := UTL_HTTP.get_response(req);
utl_http.read_text(resp,v_txt);
utl_http.end_response(resp);
RETURN v_txt;*/
RETURN 'done';
END;
/
When you need write (and read) more than 32k in utl_http, it done a bit differently.
For example:
l_data := 'fill with some sample piece of text';
http_req := utl_http.begin_request(url => 'http://example.com', method => 'POST');
utl_http.set_header (http_req, 'Content-Length', length(l_data));
utl_http.set_header (http_req, 'Content-Type', 'text/xml;charset=UTF-8');
utl_http.set_header (http_req, 'Transfer-Encoding', 'chunked');
loop
l_chunkData := null;
l_chunkData := substr(l_data, l_chunkStart, l_chunkLength);
utl_http.write_text(http_req, l_chunkData);
if (length(l_chunkData) < l_chunkLength) then exit; end if;
l_chunkStart := l_chunkStart + l_chunkLength;
end loop;
See: http://www.kurzhals.info/2012/03/using-chunked-transfer-with-plsql-utl_http-write_text.html
And for a clob example see: http://blog.optiosys.com/?p=246
You should NEVER send Transfer-Encoding: chunked , alongside Content-Length , its either the one of the other. –
Jelman
Jan 21, 2020 at 13:54
helped me!
For all of you who are struggling with similar issues, this solution also resolved the following Oracle errors:
Error: ORA-29273: fallo de la solicitud HTTP
ORA-12547: TNS:contacto perdido
for those who still need it, you can try this way :
begin
declare
v_req utl_http.req;
v_res utl_http.resp;
vn_tam_clob PLS_INTEGER;
vn_tam_buffer PLS_INTEGER;
vn_pos_inicial PLS_INTEGER;
v_buffer varchar2(32000);
v_body clob := va_content_clob; -- Your JSON (XML)
begin
-- Set connection.
vn_tam_clob := DBMS_LOB.GETLENGTH(va_content_clob);
v_req := utl_http.begin_request('http://your.api/operation', 'POST');
utl_http.set_authentication(v_req, 'your_username','your_password');
utl_http.set_header(v_req, 'content-type', 'application/json');
utl_http.set_header(v_req, 'Content-Length', vn_tam_clob);
-- Set error to exception
utl_http.set_response_error_check(true);
-- Invoke REST API.
vn_pos_inicial := 1;
vn_tam_buffer := 32000;
while vn_pos_inicial <= vn_tam_clob -- least( vn_tam_clob, vn_tam_buffer ) )
loop
utl_http.write_text( v_req, dbms_lob.substr( v_body, vn_tam_buffer, vn_pos_inicial ) );
vn_pos_inicial := vn_pos_inicial + vn_tam_buffer ;
end loop;
-- Get response para retorno OK ou analise do problema.
v_res := utl_http.get_response(v_req);
-- if you don't set : utl_http.set_response_error_check(true);
-- you can get the return structure
-- IF (v_res.status_code = 202) THEN
-- dbms_output.put_line('v_response is okay');
-- ELSE
-- dbms_output.put_line('v_resPONSE CODE IS '||v_res.status_code);
--
-- begin
-- loop
-- utl_http.read_line(v_res, v_buffer);
--
-- -- display or log in table v_buffer;
--
--
-- end loop;
-- utl_http.end_response(v_res);
-- exception
-- when utl_http.end_of_body then
-- utl_http.end_response(v_res);
-- end;
--
-- END IF;
END;
EXCEPTION
WHEN OTHERS THEN
utl_http.end_response(v_res);
RAISE;
END;

how to compare two linear lists in pascal

The task is to create new list which contains 2 linear lists, and if elements of first list equal to elements of second list then we must delete the same element from new list
procedure CreateList(var t1,L1,t2,L2:plist);
var
tmp1, tmp2:plist;
begin
t1 := L1;
t2 := L2;
while t1 <> nil do
begin
write(t1^.Data, ' ');
t1 := t1^.Next;
while t2 <> nil do
begin
write(t2^.data, ' ');
tmp2:=t2;
t2 := t2^.Next;
if(t2 = tmp1^.next) then // here is the problem how to compare 2 elements
begin
tmp1 := t1;
t1 := t1^.Next;
Dispose(tmp1);
end;
end;
end;
Writeln;
readkey;
end;
I advise you to change type of you list for something like:
type
TData = integer;
PList = ^TList;
TList = record
data : TData;
next : PList;
copy : boolean;
end;
After you will use value .copy for checking copys. Here is simple code you need.
I tried to make all code as simple as possible.
procedure deleteCopys(var list:PList);
// make all TList.copy := false (after we will use it)
var
curList : PList;
begin
curList := list;
while (curList<>nil) do
begin
curList^.copy := false;
curList := curList^.next;
End;
End;
procedure createList(var list1, list2, list3:PList);
// we belive that: (list3 is empty) and (there is no copys in list1)
// and (there is no copys in list2)
var
curList1, curList2 : PList;
begin
deleteCopys(list1);
deleteCopys(list2);
deleteCopys(list3);
// make TList.copy := true for equal elements
// from curList1 and curList2
curList1 := list1;
while (curList1 <> nil) do
begin
curList2 := list2;
while (curList2 <> nil) do
begin
if (curList1^.data = curList2^.data) then
begin
curList1^.copy := true;
curList2^.copy := true;
break;
End;
curList2 := curList2^.next;
End;
curList1 := curList1^.next;
End;
// now we can put all elements from list1 and list2
// with state TLilt.copy=false
// and each of them will be different
// (Let's do it :)
curList1 := list1;
while (curList1 <> nil) do
begin
if (curList1^.copy = false) then
begin
//some procedure for new element
putNewElement(list3, curList1^.data);
End;
End;
curList2 := list2;
while (curList2 <> nil) do
begin
if (curList2^.copy = false) then
begin
//some procedure for new element
putNewElement(list3, curList2^.data);
End;
End;
end;
I hope it will help you!