ORACLE - Exporting Procedures / Packages to a file - oracle

I would like to programmatically export my Procedures / Functions and Packages into individual files (as a backup) and using Oracle 9.2.
The closest solution i found was using DBMS_METADATA.GET_DDL , but how do i output the CLOB to a text file, without losing any parts (due to length or indentation) ?
Or maybe do you have other solutions to backup packages or other functions individually (only the one i want, not all of them) ?
Thanks

Trying to get CLOBS (and LONGS) from command line utilities like SQL*Plus always seems to give me formatting/truncation problems. My solution was to write a simple utility in a non- type checking language (Perl) that uses DBMS_METADATA to bring the CLOB back into a string.
Snippet:
...
$sthRef = $dbhRef->prepare("select dbms_metadata.get_ddl(?,?) from dual");
$sthRef->execute('PACKAGE', $thisName);
while (($thisDDL) = $sthRef->fetchrow()) {
print $thisDDL;
}
$sthRef->finish;
...

If you want to get the DDL, there really is no way except DBMS_METADATA like you already said.
Usually, this kind of a backup is done with exp (or expdp), although this doesn't create a SQL file like you would get with most other DBMS systems.

SET pages 0
spool proclist.sql
SELECT
CASE line
WHEN 1 THEN
'CREATE OR REPLACE ' || TYPE || ' ' || NAME || CHR(10) || text
ELSE
text
END
FROM user_source
WHERE TYPE IN ( 'PROCEDURE','FUNCTION')
ORDER BY name, line;
spool OFF
exit

Thanks goes for RAS , guest for his answer ,
I needed to get codes for some procedures only, so I tried the code , to find that this code truncate the code after procedure name in first line of the code and replace it with three dots '...'
so I changed the code to the following:
SELECT CASE line
WHEN 1 THEN 'CREATE OR REPLACE ' -- || TYPE || ' ' || NAME || --CHR(10) || ' ('
|| text
ELSE
text
END
FROM user_source
WHERE TYPE IN ( 'PROCEDURE') and name like 'SomeThing%'
ORDER BY name, line;
and this page
export procedures & triggers
have a very usefaul code:
connect fred/flintstone;
spool procedures_punch.lst
select
dbms_metadata.GET_DDL('PROCEDURE',u.object_name)
from
user_objects u
where
object_type = 'PROCEDURE';
spool off;
Final way to do it by using Toad Schema Browser , then select all the needed procedures and mouse right click then select export from the menu.

Related

Unequal length between strings after writing to a file - using same delimiter (tab)

I have a short procedure in PL/SQL which uses UTL_FILE package to create and then write to a .txt file.
Tab is saved in its own variable (v_delimiter), declared as varchar2(5), with a value of chr(9).
The header is saved as a string, concatenated with the v_delimiter and then written to a file.
After that, the rest of the data from an explicit cursor is also written to a file, line by line.
In the end, when I open the txt file, there are unequal widths between some of the strings which make up a header. There are also unequal widths between some of the data from the cursor inside a final .txt file and I guess that shouldn't be since I am using one and the same delimiter (tab) to create a header and to create a string from a cursor.
I am using UTL_FILE.put_line_nchar function to write a Unicode line to a file.
I tried without declaring a delimiter as a variable, using literally chr(9) when concatenating and it is always the same result.
I am out of ideas why is this happening in the final txt file.
v_file_handle UTL_FILE.file_type ;
v_output_path VARCHAR2 (100) := '/Path/to/File' ;
v_file_header VARCHAR2 (32767) ;
v_delimiter VARCHAR2 (5) := chr(9) ;
v_file_handle := UTL_FILE.fopen_nchar (v_output_path,'string_1' || TO_CHAR (SYSDATE, 'dd_mm_yyyy') || '.txt','w', 32767); -- opening
v_file_header :='claimFileIdentifier'|| v_delimiter || 'claimFileOpenedDate'
|| v_delimiter|| 'claimStatus'|| v_delimiter|| 'claimStatusDate'|| v_delimiter|| 'incidentDateTime'|| v_delimiter|| 'incidentPlace'|| v_delimiter|| 'calculationType' ... -- header
UTL_FILE.put_line_nchar ( v_file_handle, v_file_header ) ; --writing header to a file
FOR rec IN cursor_candidates --iterating over a cursor
LOOP
UTL_FILE.put_line_nchar (
v_file_handle,
rec.claimFileIdentifier
|| v_delimiter
|| rec.claimFileOpenedDate
|| v_delimiter
|| rec.claimStatus
|| v_delimiter
|| rec.claimStatusDate
|| v_delimiter
|| rec.incidentDateTime
|| v_delimiter
|| rec.incidentPlace
|| v_delimiter ... ) ; -- writing cursor rows to a file
END LOOP ;
UTL_FILE.fclose ( v_file_handle );
Final txt file and unequal width between certain strings
That's kind of expected, in my opinion. Values are separated by the TAB character, but it doesn't mean that output will look "nice" when you look at it as a text file.
For example, following values are separated by TAB, but they look ugly:
a b c
Littlefoot Scott Tiger
If you e.g. imported that file into Excel and set TAB as column separator, every value would be in its own column and output would look pretty.
If you wanted text file to look nice as well, you'll have to use a different approach, e.g. LPAD numeric values (IDs, salaries, ...), RPAD textual strings (names, addresses, ...), possibly SUBSTR (to cut long values short).
This relating to the functionality of the client application that you use to open the output tab-separated values (TSV) file.
If I have the data:
longtitle longtitle2 longtitle3
a b c
1234567890 123456789010234545 1234567788
and I open it in a basic text editor (such as Notepad) then the output is:
And the columns are unequal across the rows.
However, if I display the same data in an editor that supports TSV files (such as Notepad++) then it displays the same output with equal widths for the columns across the rows:
Importing the data into a spreadsheet application (such as Excel or OpenOffice), then the TSV is separated into cells and the output is:
And, again, the information is split into columns.
Do not change how you are outputting the file; instead, find a better way of viewing the output file with an application that supports formatting tab-separated values.

Check and delete hidden characters in file

I had a file that I was processing and it was constantly giving me errors. After some checking I realized that it had some special characters that were hidden.
I have just manually found the hidden characters and made a simple replace like
REPLACE( String,'', '')
How could I prevent this from happening in the future?
I have tried to make a table that stores these hidden ascii characters which are in the range from 125-255 but the database does not store them accordingly.
For example chr(168) is not the same as ascii 168.
select chr('168'),
convert(chr('168'),
'US7ASCII',
'WE8ISO8859P1')
from dual;
What else can I try?
Easy to write, but not the fastest to execute - using regexp_replace:
update table_name
set column_name =
regexp_replace(column_name, '[' || chr(125) || '-' || chr(255) || ']', '')
;
More efficient, but a pain in the neck to write and maintain (you can write some code to generate the code though, to save some typing):
...
set column_name =
translate(column_name, '~' || chr(125) || chr(126) || ..... || chr(255), '~')
;
Yes, with translate() you will have to spell them all out, no "range" concept... {:-(
That's to change the data already in the tables. It would be even better to fix the data as it is coming in, if you can - using a similar transformation.

Oracle Cursor Scripts errors

I have to construct a block to pull information from two tables using a cursor. As a further challenge, I have to identify the first item on the pull. I tried to use an IF statement to work through this. It errors out in several areas and I have no idea what I am doing wrong. Not asking for the answer per say, just enough of a push to get me moving again. Thanks. Here is the code I've put together so far:
DECLARE
CURSOR cur_pled IS
SELECT dd_pledge.idpledge, dd_pledge.pledgeamt, dd_pledge.paymonths, dd_payment.paydate, dd_payment.payamt
FROM dd_pledge, dd_payment
WHERE dd_payment.idpledge = dd_pledge.idpledge AND
dd_pledge.idpledge = 104
ORDER BY dd_pledge.idpledge, dd_payment.paydate;
TYPE type_pled IS RECORD
(pledID dd_pledge.idpledge%TYPE,
pledAmt dd_pledge.pledgeamt%TYPE,
payMonths dd_pledge.paymonths%TYPE,
payDate dd_payment.paydate%TYPE,
payAmt dd_payment.payamt%TYPE);
rec_pled type_pled;
lv_id_num dd_pledge.idpledge%TYPE := 0;
BEGIN
OPEN cur_pled;
LOOP
FETCH cur_pled INTO rec_pled;
EXIT WHEN cur_pled%NOTFOUND;
IF rec_pled.type <> lv_id_num THEN
DBMS_OUTPUT.PUT_LINE('First Payment');
ELSE DBMS_OUTPUT.PUT_LINE('Other Payment');
END IF;
END LOOP;
CLOSE cur_pled;
DBMS_OUTPUT.PUT_LINE(pledID || ' ' || dd_pledge.pledgeamt || ' ' ||
dd_pledge,payMonths || ' ' || dd_payment.payDate || ' ' ||
dd_payment.payAmt);
END;
There are loads of errors in your code. If you had formatted it correctly, you would have spotted some of them yourself!
Things that leapt out at me:
You're referring to dd_pledge in the final dbms_output.put_line, but dd_pledge isn't a variable. I think you meant to use rec_pled instead.
You refer to pledID in your final dbms_output.put_line statement - but this is a field defined in the record type, NOT a defined variable. I think you probably meant to use rec_pled.pledid
You're selecting the results of the cursor into rec_pled.type - however, "type" is not a field declared in the type_pled's definition! Did you mean rec_pled.idpledge instead?
You have dd_pledge,payMonths in your final dbms_output.put_line statement - the comma should be a full stop: rec_pled.payMonths
You're outputting the results after you've closed the results. Because this is just a record variable, you're only going to be outputting the results from the last row in the query.
Why aren't you doing a cursor for loop? That takes care of the exiting and declaring a record for you.
Anyway, I think you can achieve your results by using an analytic function in your query, rather than needing to use PL/SQL to do the work:
SELECT plg.idpledge,
plg.pledgeamt,
plg.paymonths,
pay.paydate,
pay.payamt,
case when row_number() over (partition by plg.idpledge, pay.paydate) = 1 then 'First Payment'
else 'Other Payment'
end type_of_payment
FROM dd_pledge plg
inner join dd_payment pay on (pay.idpledge = plg.idpledge)
--WHERE plg.idpledge = 104 -- add back in if you really need to do it for a single id
ORDER BY plg.idpledge, pay.paydate;

use BTEQ to schedule a query in windows

Hi I'm pretty new using BTEQ,
I'm looking to schedule a query that runs using teradata connection, the query results should go to an excel or txt with separators (so it can be formatted using excel)
I need to to this through windows, so I guess it should be a *.bat scheduled using windows scheduler
The things is that I don't have a clue how to open the connection, running the query and exporting the result to a *.xls or *.csv or *.txt
I have set already the ODBCs to connect to TD (I use the TD administrator and run the query manually everyday).
Any ideas?
BTEQ doesn't use ODBC but a CLI connection.
You can simply create a script like this:
.logon TDPID/username,password;
.OS if exist bla.txt del bla.txt; -- remove the file if it exists (otherwise BTEQ appends)
.export report file = bla.txt;
SELECT
TRIM(DataBaseName) || ',' ||
TRIM(TableName) || ',' ||
TRIM(Version) || ',' ||
TRIM(TableKind) || ',' ||
TRIM(ParentCount) (TITLE '')
FROM dbc.TablesV
SAMPLE 10
;
.export reset;
.EXIT;
TDPID is the name of your TD system (or an IP-address).
You need to manually format the csv in the SELECT as shown above using TRIM and || and you have to take care of possible NULLs using COALESCE(TRIM(col), '').
You might also try the ancient DIF format, no need to care about NULLs, etc.
.export DIF file = bla.dif;
SELECT
DataBaseName
,TableName
,Version
,TableKind
,ParentCount
FROM dbc.TablesV
SAMPLE 10
;
In TD14 there's a table UDF named CSV which takes care for NULLs and quoting strings instead of TRIM/COALESCE/||. Thy syntax is a bit lengthy, too:
WITH cte
(
DataBaseName
,TableName
,Version
,TableKind
,ParentCount
)
AS
(
SELECT
DataBaseName
,TableName
,Version
,TableKind
,ParentCount
FROM dbc.TablesV
SAMPLE 10
)
SELECT *
FROM TABLE(CSV(NEW VARIANT_TYPE
(
cte.DataBaseName
,cte.TableName
,cte.Version
,cte.TableKind
,cte.ParentCount
), ',', '"')
RETURNS (op VARCHAR(32000) CHARACTER SET UNICODE)) AS t1;
Finally you run BTEQ and redirect the file (you can put this is an BAT file):
BTEQ < myscript.txt
There might be other options, too, e.g. a TPT/FastExport script or putting the SQL inside an Excel file which automatically runs the query when opened...

Error with LONG data type in cursor

I am trying to generate a spool file through anonymous block below in order to find out views on a particular table.
declare
cursor c1 is select view_name,text from users_view;
rt c1%rowtype;
begin
open c1;
loop
fetch c1 into rt;
exit when c1%notfound;
dbms_output.put_line(rt.view_name || '|' || rt.text);
end loop;
end;
When I run it, I get an error like "numeric or value errors", however if I remove text(LONG) column from cursor definition the block goes through without any error.
I understand that we can not use LONG data type in a where clause but is it that it can't be fetched in a cursor as well? If yes, what can be the alternative in this case?
Not directly addressing the long issue, but if you want to find out which views refer to a particular table, rather than searching through the view source you can query the data dictionary:
select owner, type, name
from all_dependencies
where referenced_type = 'TABLE'
and referenced_owner = user -- or a specific schema
and referenced_name = '<my_table_name>';
This will also list any triggers on the table, etc., so if you are only interested in view you can add and type = 'VIEW'.
Of course, this may just give you a smaller list of views to examine in more detail to see how the table is used by each one, but it's easier than searching all 300 of your views manually... and it might mean you don't need to get the text of the large views with more than 32k characters which are causing the long problem in the first place.
In this case the error indicates that you've hit the buffer limit - dbms_output.put_line wont handle such large amount of data.
After looking at the problem more closely, it's not the dbms_output.put_line issue, not yet, it's the, as Alex Poole has pointed out in the comment to your question, it's the cursor problem. So I would suggest you to use simple Select statement(option #2 in the answer). If you go for a workaround
create table <<name>> as
select view_name
, to_lob(text)
from user_views
for example, you will be able to use cursor but then dbms_output.put_line will stop you
To generate a spool file you have at least two options:
Use UTL_FILE package to write data to a file.
Let SQL*PLUS do the job. For example:
set feedback off;
set termout off;
set colsep "|";
set long 20000; -- increase the size if it's not enough
set heading off;
set linesize 150; -- increase the size if it's not enough
spool <<file path\file name>>
select view_name
, text
from user_views
spool off;
At the end you will have a similar output in your <<file path\file name>> file:
ALL_APPLY_CONFLICT_COLUMNS |select c.object_owner,
| c.object_name,
| c.method_name,
| c.resolution_column, c.column_name,
| c.apply_database_link
| from all_tab_columns o,
| dba_apply_conflict_columns c
| where c.object_owner = o.owner
| and c.object_name = o.table_name
| and c.column_name = o.column_name

Resources