This link explains how to show an image from a BLOB in a table, to a Display image item
http://www.apexninjas.com/blog/2011/09/uploading-and-displaying-images-in-apex/
It advises to write this code (the code converts BLOB data into HTML):
create or replace PROCEDURE image(image_id IN NUMBER)
AS
l_mime VARCHAR2 (255);
l_length NUMBER;
l_file_name VARCHAR2 (2000);
lob_loc BLOB;
BEGIN
SELECT i.MIME_TYPE, i.CONTENT, DBMS_LOB.getlength (i.CONTENT), i.FILENAME
INTO l_mime, lob_loc, l_length, l_file_name
FROM EMP_IMAGE i
WHERE i.ID = image_id;
OWA_UTIL.mime_header (NVL (l_mime, 'application/octet'), FALSE);
htp.p('Content-length: ' || l_length);
htp.p('Content-Disposition: filename="' || SUBSTR(l_file_name, INSTR(l_file_name, '/') + 1) || '"');
owa_util.http_header_close;
wpg_docload.download_file(Lob_loc);
END image;
I'm new to Oracle APEX 5, and I do not understand where in the interface should I write that code
My UI loos like this
https://i.imgur.com/7xCRO7U.png
They're telling you to create that procedure in the database; it's not an APEX component. I don't think I would recommend their approach of opening a security hole to allow direct execution of a custom local procedure. And it's not necessary anymore; APEX has changed a lot since 2011.
On the left, click your Display Image item named "IMAGE". Then on the right, under "Settings", change the "Based On" to BLOB Column returned by a SQL Statement, and just put a query in there that'll return the column you want.
You'll need a primary key to find the right row; here I'm assuming that you're using the FILE_NAME page item, but probably a better option would be to have a hidden page item to hold the primary key from your IMAGES table, maybe called "P1_ID" for an "id" column, and add RETURNING id INTO :P1_ID to the end of your INSERT statement in your page process. Then your "IMAGE" page item query will look something like:
SELECT i.CONTENT
FROM IMAGES i
WHERE i.ID = :P1_ID;
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 have text stored in a database table, many short rows about 70-90 characters long fields. (of historical reasons). I want to append these fields (rows) into an CLOB in an APEX (CKEditor) and it does exeed 32k in many cases.
I have tried in many ways but it seems to be some limit. My code works fine as long the text is less than 32k! My plan is to save it in a new table and there use a clob instead. I have APEX 5.01.
I get 'ORA-06502: PL/SQL: numeric or value error' when it is over 32k.
declare
l_clob CLOB;
l_seq number;
cursor textrader_cur is
SELECT F1NR,FHTTYP,RADNR,FHTEXT,DATUM,UPPTAGEN,NUSER FROM DATATXT WHERE DATATXT.F1NR = :P10_F1NR ORDER BY F1NR,FHTTYP,RADNR;
TYPE datatext_typ IS TABLE OF DATATXT%ROWTYPE INDEX BY PLS_INTEGER;
l_datatext datatext_typ;
begin
l_clob := empty_clob();
DBMS_LOB.CREATETEMPORARY(l_clob,true);
apex_collection.create_or_truncate_collection(p_collection_name => 'TEXT');
select count(1) into x from DATATXT#HUMANAUTV WHERE DATATXT.F1NR = :P10_F1NR;
if x > 0 then
open textrader_cur;
loop
fetch textrader_cur bulk collect into l_datatext LIMIT 200;
for indx in 1..l_datatext.COUNT loop
y := length(l_datatext(indx).fhtext);
dbms_lob.writeappend (l_clob,y,l_datatext(indx).fhtext);
--l_clob := l_clob || l_datatext(indx).fhtext; -- This causes same error
end loop;
EXIT WHEN l_datatext.COUNT = 0;
end loop;
close textrader_cur;
l_seq := apex_collection.add_member(p_collection_name => 'TEXT',
p_d001 => sysdate,
p_d002 => sysdate,
p_n001 => dbms_lob.getlength(l_clob),
p_clob001 => l_clob);
-- :P10_WP := l_clob;
SELECT clob001 into :P10_WP FROM APEX_COLLECTIONS WHERE SEQ_ID = l_seq AND COLLECTION_NAME='TEXT';
end if;
end;
PL/SQL provides a dbms_lob package to manipulate this data type. The way I had addressed in a different technology (zope/python) similar problem was to create a framework:
To read from db, it returned data as multipe rows
To write to db, it would send data as multipel calls and server eventually combined it.
You can see that here Blob Journey from Database To Browser
The problem is the last line in your code. Session state variables (e.g. P10_WP) are all VARCHAR2, and limited to 32767 characters. You can see that in the APEX functions that call them (example). So you can't assign more than 32k characters to a PL/SQL page item.
But obviously you can put more than 32k characters in an HTML form item! So it's an awkward workaround - you have to get the clob data in and out of the HTML form item without using APEX page items. Typically this is done by writing the clob to a Collection, then using AJAX calls to an Application Process to retrieve it, since JavaScript has no problem with character limits.
It looks like you've gotten partway there on your own, with your TEXT collection, but you'll still have to write your own On-Demand Application Process so you can load the collection into JavaScript, and put it in the HTML form item from there. It'll be easier if you use the built-in apex.ajax.clob functionality with the CLOB_CONTENT collection.
I looked over a few articles about this, and this one is pretty well written and straightforward.
The short version is to change your collection name in your code to CLOB_CONTENT, then put this JavaScript function on your page and call it.
function clob_get(){
var clob_ob = new apex.ajax.clob(
function(){
var rs = p.readyState
if(rs == 1||rs == 2||rs == 3){
$x_Show('AjaxLoading');
}else if(rs == 4){
$s('P10_WP',p.responseText);
$x_Hide('AjaxLoading');
}else{return false;}
}
);
clob_ob._get();
}
PL/SQL in APEX are limited to 32k, pl/sql treats clobs as varchar and thats it. My problem cannot be solved within APEX
I am building an Oracle ApEx page to show charts of data. The data are entered on to a table as inputs, but the actual calculated metric can be different depending on what KPI is being viewed (AVG(VALUE_1); SUM(VALUE_1)/SUM(VALUE_2); etc.); these calculations are stored on a separate table. Since I want everything to be dynamic for use interactions, I am using a source of PL/SQL Function Body returning SQL Query. Here is a simplified version
DECLARE
SQL_STMT VARCHAR2 (32767);
CALC_CLAUSE VARCHAR2 (4000);
BEGIN
SELECT CALCULATION
INTO CALC_CLAUSE
FROM KPI_TYPES
WHERE ID = 101;
--when the value itself is entered, the results display as intended
SQL_STMT := 'SELECT DATE, ' || CALC_CLAUSE || ' KPI_VALUE
FROM DATA_VALUES
WHERE TYPE_ID = :P_KPI
GROUP BY DATE';
RETURN SQL_STMT;
END;
As noted above, this functions as expected when the KPI's ID is manually entered, but I want this to be dynamic. I have a select list page item (P_KPI) for the user to choose the viewed KPI. Its value is actually set from a previous page with validation, so it should never be null.
When I update the CALC_CLAUSE condition:
WHERE ID = :P_KPI
I receive the following error:
ORA-01403: no data found
How can I reference this page item in the function?
Code you posted is invalid (wouldn't compile) and explanation you gave is wrong. Although it is a simplified version, I'd prefer if you posted accurate information.
You said that SQL statement is
SELECT DATE, '||CALC_CLAUSE||' KPI_VALUE
FROM DATA_VALUES ...
while CALC_CLAUSE looks like
WHERE ID = :P_KPI
so the whole query looks like
SELECT DATE, WHERE ID = :P_KPI KPI_VALUE
FROM DATA_VALUES ...
which just doesn't make sense. What is that CALC_CLAUSE, after all? Shouldn't it be AVG(VALUE_1) or something like that?
As of :P_KPI item whose value seems to be NULL: it doesn't matter that you see it on the screen - it should be in the session state. The simplest way to do that is to submit the page, so - did you do it?
Try to create a stored function (in the database, not in Apex) and pass it P_KPI value as a parameter. Then test what you get, as well as the result. When working with dynamic SQL, it is a good idea to DBMS_OUTPUT.PUT_LINE the resulting statement (that would be SQL_STMT in your example), copy/paste it into SQL*Plus (or any other tool you use, such as SQL Developer) and see whether it works correctly.
For example:
CREATE OR REPLACE FUNCTION f_stmt (par_kpi IN NUMBER)
RETURN VARCHAR2
IS
sql_stmt VARCHAR2 (32767);
calc_clause VARCHAR2 (4000);
BEGIN
SELECT calculation
INTO calc_clause
FROM kpi_types
WHERE id = par_kpi;
sql_stmt :=
'SELECT DATE, '
|| calc_clause
|| ' KPI_VALUE '
|| ' FROM DATA_VALUES '
|| ' WHERE TYPE_ID = '
|| par_kpi
|| ' GROUP BY DATE';
DBMS_OUTPUT.put_line (sql_stmt);
RETURN sql_stmt;
END;
Starting with the stored function suggested by Littlefoot, I was able to use this solution:
http://vincentdeelen.blogspot.com/2014/02/interactive-report-based-on-dynamic-sql.html
I have a page process that creates a collection with the dynamic query string. The charts region SQL now queries from the collection, and I can use all of my page items to filter the data appropriately.
my Oracle SqlDeveloper (or Oracle Database?) doesn't know the :NEW keyword.
For instance, if I enter the following sample from Oracles website,
when I execute the "create or replace trigger" paragraph, a window "Enter bind variable" pops up and asks for the bind variable ":new".
Shouldn't this ":new" variable be predefined?
(Oracle SQL Developer 4.0.1.14, Oracle DB 11gR2, Windows)
drop table tab1;
create table tab1 (c1 clob);
insert into tab1 values ('testtext');
create or replace trigger trg1
before update on tab1
for each row
begin
dbms_output.put_line('Old value of CLOB column: '||:OLD.c1);
dbms_output.put_line('Proposed new value of CLOB column: '||:NEW.c1);
-- Previously, we couldn't change the new value for a LOB.
-- Now, we can replace it, or construct a new value using SUBSTR, INSTR...
-- operations for a CLOB, or DBMS_LOB calls for a BLOB.
:NEW.c1 := :NEW.c1 || to_clob('<hr><p>Standard footer paragraph.');
dbms_output.put_line('Final value of CLOB column: '||:NEW.c1);
end;
/
set serveroutput on;
update tab1 set c1 = '<h1>Different Document Fragment</h1><p>Different text.';
select * from tab1;
It turned out I just had to press "Apply" in the Bind dialog, and the trigger was created. Obviously a bug in SqlDeveloper. At least there is a workaround...
I added the 'REFERENCING' statement, and tested the code, seems to work just fine--- BTW, you can just turn DBMS output on in SQL dev w/o having to run the command..
CREATE OR REPLACE TRIGGER trg1
BEFORE UPDATE
ON tab1
REFERENCING NEW AS new OLD AS old
FOR EACH ROW
BEGIN
DBMS_OUTPUT.put_line ('Old value of CLOB column: ' || :old.c1);
DBMS_OUTPUT.put_line ('Proposed new value of CLOB column: ' || :new.c1);
-- Previously, we couldn't change the new value for a LOB.
-- Now, we can replace it, or construct a new value using SUBSTR, INSTR...
-- operations for a CLOB, or DBMS_LOB calls for a BLOB.
:new.c1 := :new.c1 || TO_CLOB ('<hr><p>Standard footer paragraph.');
DBMS_OUTPUT.put_line ('Final value of CLOB column: ' || :new.c1);
END;
I'm designing an HTML report that effectively extracts columns from a single table
The number of columns in this table is quite large, and I would like some way to configure the application to say which columns to display. Note: This is not a per-user setting.
Lets say I have the main table:
MAIN_TABLE
id
first_name
last_name
weight
height
attribute_4
attribute_5
attribute_6
...
attribute_99
I was thinking of a table like
MAIN_TABLE_DISPLAY
column_name
display
Or perhaps
MAIN_TABLE_DISPLAY
display_id
display_first_name
display_last_name
display_weight
display_height
display_attribute_4
display_attribute_5
display_attribute_6
...
display_attribute_99
But I would like to perform an efficient join.
Any suggestions?
Thanks.
Dynamic column inclusion/exclusion == dynamic SQL.
This solution might give you some ideas.
http://tkyte.blogspot.com/2006/01/i-like-online-communities.html - he passes a ref_cursor to a function that returns a CLOB that is fully formatted HTML table with full resultset of that ref_cursor. All in less than 100 lines.
Have you thought about using a view? Your application can pull it's data from there, and to change which columns you're showing, change the view. You would have to change the presentation side of things to account for the different columns also.
As jva said, you'll need to use dynamic SQL. Something like this (with the appropriate bug fixes) should do it:
type column_table is table of varchar2(30);
function table_as_html(table_name varchar2, columns column_table) return clob is
sql_query varchar2(32767);
sql_cursor sql_refcursor;
html_row clob;
html_text clob;
begin
sql_query := 'select ''<tr>';
for column in 1 .. columns.count loop
sql_query := sql_query||'||''<td>''||'||columns(column)||'||''</td>'''
end loop;
sql_query := sql_query||'||''</tr>'' from '||table_name;
open sql_cursor for sql_query;
loop
fetch sql_cursor into html_row;
exit when sql_cursor%notfound;
html_text := html_text||html_row||chr(10);
end loop;
close sql_cursor;
return html_text;
end;