I have a problem, in my ORACLE APEX app, I want to have file uploading mechanism that send uploaded .zip file as parameter to some function (that function works well, I tested it by manual feeding from DB). Problem is, when I try to select uploaded file from "apex_application_temp_files" in a process it throws exception "NO DATA FOUND", but when I add report to app where I select ID and FILENAMES I see that file...any idea why this is happen?
I am sorry if this is some trivial issue, but I am pretty new in APEX developing.
The process:
declare
l_blob blob;
begin
SELECT blob_content
INTO l_blob
FROM apex_application_temp_files
WHERE NAME = :P6_FILE;
--INSTANTLY SET :G_TEST_ID FOR REPORTS
:G_TEST_ID := file_management.unwrap_zip(ab_zipped_blob => l_blob);
end;
You need to select on column NAME instead of FILENAME. The former is the unique identifier (looks like series_of_numbers\the_filename) and is what the file browse item will contain, while the latter is without the prefix.
Look, you'll have to provide more information from your end. I've created a really simple page to try this (apex.oracle.com).
P2_FILE is a file-browse item.
Storage Type: Table APEX_APPLICATION_TEMP_FILES
Purge File at: End of Session
I've created an on-submit process which does nothing more than list some things in the debug output.
declare
l_blob blob;
begin
for r in (select * from apex_application_temp_files)
loop
apex_debug.message('name: %s - filename: %s', r.name, r.filename);
end loop;
apex_debug.message('P2_FILE: %s', :P2_FILE);
SELECT blob_content
INTO l_blob
FROM apex_application_temp_files
WHERE name = :P2_FILE;
apex_debug.message('blob length: %s', dbms_lob.getlength(l_blob));
end;
So I run the page, enable debug, select a file and hit submit. All works. Check the debug log (accept):
name: 39044609744029199463/README (2).md - filename: README (2).md
name: 39044529927808550681/README (1).md - filename: README (1).md
name: 39044569042020557797/README.md - filename: README.md
P2_FILE: 39044609744029199463/README (2).md
blob length: 1884
So: what's different at your end? Have you done as suggested by Jeffrey and run a debug of the page? What is your "purge" set as? Are you sure the no-data-found occurs on select of the blob and not in your procedure - have you commented out your procedure call yet?
Related
I have an Interactive Report with column having arabic Characters displaying well in the Report , however i am exporting the Reports into csv but the arabic characters turns to ????? in csv file , Any suggestions or workaround i may follow either at Interactive Report level or query level or this something csv don't support.
I am not entirely sure, but I think the problem might happen because the Java script function associated with Actions Menu --> Download might not take in consideration the encoding on database side, rather than the one on client side.
Normally, when I want to control the export to csv from a page, I disable the actions menu to avoid that the user can do it using that menu, instead I prefer to create a PL/SQL procedure to be triggered by an application express process.
How to do that ?
Download CSV File Using PL/SQL Procedure and Application Process in Oracle Apex
In order to do this , follow the instructions:
1.Create a PL/SQL Procedure
Create a database procedure which will return the CSV as CLOB data.
create or replace procedure tab_to_csv(o_Clobdata OUT CLOB) IS
l_Blob BLOB;
l_Clob CLOB;
BEGIN
Dbms_Lob.Createtemporary(Lob_Loc => l_Clob,
Cache => TRUE,
Dur => Dbms_Lob.Call);
SELECT Clob_Val
INTO l_Clob
FROM (SELECT Xmlcast(Xmlagg(Xmlelement(e,
Col_Value || Chr(13) ||
Chr(10))) AS CLOB) AS Clob_Val,
COUNT(*) AS Number_Of_Rows
FROM (SELECT 'your columns for the header split by the separator' AS Col_Value
FROM Dual
UNION ALL
SELECT col1||',' ||col2||','|| col3||','|| col4||','|| col5||','|| col6 as Col_Value
FROM (SELECT col1,col2,col3,col4,col5,col6 from yourtable)));
o_Clobdata := l_Clob;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/
You can adapt that procedure the way you want. I use header, so that is the reason for the first select. In my example, the separator was , , but you can use another one if you like, or even use a parameter for it instead.
2.Create an Application Process in Oracle Apex
In Oracle Apex, click on the Shared Components --> Application Process and then click on the Create button. Then follow these steps:
Then press next and put the following code
DECLARE
L_BLOB BLOB;
L_CLOB CLOB;
L_DEST_OFFSET INTEGER := 1;
L_SRC_OFFSET INTEGER := 1;
L_LANG_CONTEXT INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
L_WARNING INTEGER;
L_LENGTH INTEGER;
BEGIN
-- create new temporary BLOB
DBMS_LOB.CREATETEMPORARY(L_BLOB, FALSE);
--get CLOB
tab_to_csv( L_CLOB);
-- tranform the input CLOB into a BLOB of the desired charset
DBMS_LOB.CONVERTTOBLOB( DEST_LOB => L_BLOB,
SRC_CLOB => L_CLOB,
AMOUNT => DBMS_LOB.LOBMAXSIZE,
DEST_OFFSET => L_DEST_OFFSET,
SRC_OFFSET => L_SRC_OFFSET,
BLOB_CSID => NLS_CHARSET_ID('WE8MSWIN1252'),
LANG_CONTEXT => L_LANG_CONTEXT,
WARNING => L_WARNING
);
-- determine length for header
L_LENGTH := DBMS_LOB.GETLENGTH(L_BLOB);
-- first clear the header
HTP.FLUSH;
HTP.INIT;
-- create response header
OWA_UTIL.MIME_HEADER( 'text/csv', FALSE, 'AL32UTF8');
HTP.P('Content-length: ' || L_LENGTH);
HTP.P('Content-Disposition: attachment; filename="yourfile.csv"');
HTP.P('Set-Cookie: fileDownload=true; path=/');
OWA_UTIL.HTTP_HEADER_CLOSE;
-- download the BLOB
WPG_DOCLOAD.DOWNLOAD_FILE( L_BLOB );
-- stop APEX
-- APEX_APPLICATION.STOP_APEX_ENGINE;
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FREETEMPORARY(L_BLOB);
RAISE;
END;
After that click on the Next button and on the next screen click on the Create button to finish the wizard. Your application process has been created.
3.Create a Button on a Page in Oracle Apex
Now open a page in Page designer in Oracle Apex in which you want to add a button to download the CSV file.
Then do the right-click on the Region and click on the option Create Button.
Set the Action to Redirect to URL.
Paste the following URL in the URL target.
f?p=&APP_ID.:0:&SESSION.:APPLICATION_PROCESS=download_emp_csv:NO
Notice that we are calling the application process download_emp_csv, we just created in the second step.
Now save the changes and run the page. On click of the button, the CSV file will be download.
I've got a question how to import a .csv file into a Oracle Forms application.
We are using Oracle Forms 11g on a Oracle 12c Database.
Now we want to import a .csv file with the Forms applicationso our customers can import this file and write the data into the database.
My plan is to create an application where the user can import a .csv file with a filechooser. The data from the .csv will be read and an output shows the user the data in this application. Then the user should be able to save it into the database through a button.
I've tried several searches but haven't found the right solution for this kind of problem. The only solutions I've found were a direct import of a .csv file into a database but not through Oracle Forms
Is it even possible to load .csv files in Oracle Forms?
If anyone has a good solution or anything else that might be helpfull i would be thankfull for that.
I've found a suitable solution for me now. Maybe I could do it better but this helps me so far.
I've found the following Blog: http://tfathy.blogspot.de/2009/03/reading-from-file.html
The Code works 100% by copy&paste and helps me from now on to complete the task.
Maybe it might help anyone else too.
Here is the solutioncode:
Reading From File
March 19, 2009
--------------------------------------------------
Declare
vfilename varchar2(500);
in_file Client_Text_IO.File_Type;
linebuf VARCHAR2(1800);
BEGIN
vfilename := client_get_file_name('c:/temp/', File_Filter=>'Comma Dialimeted Files (*.csv)|*.csv|');
in_file := client_Text_IO.Fopen(vfilename, 'r');
GO_BLOCK('Emp');
FIRST_RECORD;
LOOP
Client_Text_IO.Get_Line(in_file, linebuf);
p_output_line(linebuf);
Client_Text_IO.New_Line;
Next_record;
END LOOP;
FIRST_RECORD;
EXCEPTION
WHEN no_data_found THEN
Client_Text_IO.Put_Line('Closing the file...');
Client_Text_IO.Fclose(in_file);
END;
-------------------------------------------------------
PROCEDURE p_output_line(p_line varchar2) IS
vLINE VARCHAR2(4000);
vVALUE VARCHAR2(1000);
vCOMMA_COUNT NUMBER;
vREPORT_DATE DATE;
BEGIN
vLINE := p_line;
vCOMMA_COUNT := LENGTH(vLINE)- LENGTH(REPLACE(vLINE,',','')); -- COUNT THE NUMBER OF COMMAS
FOR I IN 1.. vCOMMA_COUNT+1 LOOP
vVALUE := SUBSTR(vLINE,1,INSTR(vLINE,',')-1); -- IF vLINE = 123,ABC,9877 THEN VVALUE WILL BE 123
IF vVALUE IS NULL THEN
vVALUE := vLINE;
END IF;
vLINE := SUBSTR(vLINE,INSTR(vLINE,',')+1) ; -- CHANGE 123,ABC,9877 TO BE ABC,9877
IF I = 1 THEN
:DATA.BMK_NAME := vVALUE;
ELSIF I = 2 THEN
vREPORT_DATE := last_day(to_date(vVALUE,'dd-mm-yyyy'));
:DATA.REPORT_DATE := vREPORT_DATE;
ELSIF I = 3 THEN
:DATA.BMK_RETURN := to_number(vVALUE);
END IF;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
MESSAGE('Please Check the data type is appropriate on you excel file');
MESSAGE('Please Check the data type is appropriate on you excel file');
END;
-----------------------------------------------------------------------
-- notes
1- you must install webutil version 106 or later
2- make sure that you attached and compiled the webutill.pll scucessfuly
You can just use webutil to show a filechooser to select the file and upload it to the application server. If you use a shared directory between the application server and the db server you can use an external table to show the input of the file to the user. And then after the button you just insert the data from the external table in another table.
I want to know what's the way to create a log file which will contain the rejected records with the reason behind it.
Suppose for example
**EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY,MANAGER_ID**
100,Steven,King,24000,NULL
101,Neena,Kochhar,35000,100
I want to reject those reocrds where an employee salary is greater than his/her manager's. so record with employee_id 101 will be rejected.
How can I create a log file that will contain information like
101,Neena,Kochhar,Salary can't be greater than manager's,100
Please guide me.. I have already created the scripts necessary to load the data into external table..
One way to create a log file is to use the UTL_FILE package to open a log file, write whatever you want, and close the log file. For example:
CREATE PROCEDURE PROCESS_RECORDS IS
fErr_log UTL_FILE.FILE_TYPE;
BEGIN
fErr_log := UTL_FILE.FOPEN(SOME_DIRECTORY_OBJECT, 'your_filename_here.log', 'w');
FOR eachRecord IN (SELECT * FROM SOME_TABLE)
LOOP
IF eachRecord.SOME_FIELD NOT IN ('LIST', 'OF', 'VALID', 'VALUES') THEN
-- Write error log entry
UTL_FILE.PUT_LINE(fErr_log,
eachRecord.KEY || ',' ||
eachRecord.FIRSTNAME || ',' ||
eachRecord.LASTNAME || ',' ||
'SOME_FIELD not in list of valid values');
END IF;
END LOOP;
UTL_FILE.FCLOSE(fErr_log);
END PROCESS_RECORDS;
Share and enjoy.
Im doing a college assignment that requires me to create a PLSQL procedure that where the user can add a new customer order containing a number of items and the quantity for each item. I came up with the following that would ask the user to input a number of items to be added to the order and would then use a loop to ask for specific details such as product no and quantity. Im having problems with the user input at runtime though... When compiling the code it asks for the product code and quantity and wont ask again at runtime instead it saves the values given earlier at compile...
CREATE OR REPLACE
PROCEDURE Add_Order (Item_amount IN NUMBER, CustNo IN NUMBER) AS
ItemNo NUMBER;
var_Quantity NUMBER;
var_PONo NUMBER;
BEGIN
IF Item_amount BETWEEN 2 AND 9 THEN
SELECT seq_PONo.NEXTVAL INTO var_PONo from dual;
INSERT INTO PurchaseOrder_tab
SELECT var_PONo, REF(C),
SYSDATE,
ItemList_tab()
FROM Customer_tab C
WHERE C.CustNo = CustNo;
FOR i IN 1..Item_amount LOOP
DBMS_OUTPUT.PUT_LINE('INSIDE LOOP');
ItemNo := &Enter_ProdCode;
var_Quantity := &Quantity_Amount;
INSERT INTO TABLE (
SELECT P.ItemList
FROM PurchaseOrder_tab P
WHERE P.PONo = var_PONo
)
SELECT seq_ItemNo.nextval, REF(Pr), var_Quantity
FROM Products_tab Pr
WHERE Pr.ProductCode = ItemNo ;
DBMS_OUTPUT.PUT_LINE('Added '||var_Quantity ||' items of '||ItemNo||' to order No: '||var_PONo);
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE('Amount of items entered onto an order must be between 2 - 9. Please try again with correct amount.');
END IF;
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Operation failed '||'SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('SQL Error Message '||SQLERRM);
ROLLBACK;
END;
/
Short answer: you can't. PL/SQL is executed inside the database engine, and the database engine has no access to the terminal window (or database tool) you are using to start the procedure.
The code in your quesion seems to partially work, because it asks for input once, but what really happens is that: the tool (SQL*Plus, SQL Developer or whatever) parses over the PL/SQL block and sees the &-Signs, so it asks what to replace them with. Once the input is given, the PL/SQL-Block - including the entered values - is given to the database for execution.
Since you can't do that in PL/SQL, better create a front-end program first that collects the values, then sends them to the database.
Try to play around with :
BEGIN
DBMS_OUTPUT.GET_LINE(:buffer, :status);
END;
Instead of using & refferences
To Get data input from the USer,
SET SERVEROUTPUT ON;
ACCEPT Enter_ProdCode VARCHAR2 PROMPT "Please enter Product code : ";
ItemNo := &Enter_ProdCode;
I created a simple Oracle type:
create or replace TYPE MY_TYPE AS OBJECT (ID NUMBER(30), NAME VARCHAR2(20));
Then, I created a second table type:
create or replace TYPE MY_TYPE_TABLE AS TABLE OF MY_TYPE;
Finally, I created a simply function:
create or replace FUNCTION my_function(line_id IN NUMBER) RETURN MY_TYPE_TABLE
AS
return_data MY_TYPE_TABLE := MY_TYPE_TABLE();
BEGIN
return_data.EXTEND;
return_data(return_data.count) := (MY_TYPE(10, 'BOB')) ;
return_data.EXTEND;
return_data(return_data.count) := (MY_TYPE(11, 'ALAN')) ;
RETURN return_data;
END SETTLEMENT_NET_TRACKING;
My question: How to run this function that result like this:
10 BOB
11 ALAN
Hot to do it?
If you're looking for logging in that method you could use DBMS_OUTPUT to log to the standard output or use UTL_FILE to log to a file. I've suggested in previous questions that if you're designing anything bigger than a trivial application you'll want to create a custom logging package.
For your problem it would look something like this:
dbms_output.enable;
for i in return_data.first..return_data.last loop
dbms_output.put_line(return_data(i).id || ' ' || return_data(i).name);
end loop;
You'll need to enable output in your client application. For SQLPlus you'd use SET SERVEROUT ON before you call your API.
You can also do
select * from table(my_function(30))