{"id":2881,"date":"2019-03-14T17:13:07","date_gmt":"2019-03-14T14:13:07","guid":{"rendered":"https:\/\/sysdba.org\/?p=2881"},"modified":"2019-03-14T17:13:07","modified_gmt":"2019-03-14T14:13:07","slug":"procedure","status":"publish","type":"post","link":"https:\/\/sysdba.org\/en\/procedure\/","title":{"rendered":"Procedure"},"content":{"rendered":"<p>Procedure<br \/>\nProcedures can be used for Insert, Update and Delete operations. As their structures aren&#8217;t suitable, they aren&#8217;t used that often for Select operations.<\/p>\n<p>It is possible to specify the action to apply such as a drop or purge, on a user basis, when they want to delete a table by saving it into a procedure and enforcing it.<\/p>\n<p>This is decided upon by the database administrator.<br \/>\n[crayon]create or replace procedure drop_table (p_tablename varchar2) is<br \/>\nbegin<br \/>\nexecute immediate &#8216;drop table &#8216; || p_tablename || &#8216; purge&#8217; ; &#8212; has to be coded as &#8216; purge&#8217;. Its necessary to have a single space between the &#8216; and purge.<br \/>\ndbms_output.put_line(p_tablename || &#8216; table has been dropped. &#8216;);<br \/>\nend;<br \/>\nbegin<br \/>\ndrop_table (&#8217;employees_2&#8242;) ;<br \/>\nend;[\/crayon]<br \/>\nCan alternatively be run as:<br \/>\n[crayon]exec drop_table(&#8217;employees_3&#8242;);<br \/>\ncreate or replace procedure add_dept (p_deptid number, p_deptname varchar2) is<br \/>\nbegin<br \/>\ninsert into dept(department_id, department_name) &#8212; As this is a DDL command, it can be written directly without an exec<br \/>\nvalues (p_deptid, p_deptname);<br \/>\ncommit;<br \/>\nend;<br \/>\nexec add_dept(800, &#8216;eighthundred&#8217;)<br \/>\nselect upper(&#8216;ibrahim\u0130BRAH\u0130M&#8217;) from dual; &#8212;&#8211;&gt; IBRAHIM\u0130BRAH\u0130M<br \/>\nselect lower(&#8216;I\u011eDIR\u0131\u011fd\u0131r\u0130BRAH\u0130M&#8217;) from dual; &#8212;&gt; i\u011fdir\u0131\u011fd\u0131r\u0131brah\u0131m[\/crayon]<br \/>\nThis is a bug in Oracle.<br \/>\n[crayon]select &#8216;ismail&#8217; from dual;<br \/>\nselect replace(&#8216;ismail&#8217;,&#8217;i&#8217;,&#8217;\u0130&#8217;) from dual;[\/crayon]<br \/>\nA workaround is to replace the lowercase i&#8217;s<br \/>\n[crayon]select upper(&#8216;ibrahim\u0130BRAH\u0130M&#8217;) from dual;<br \/>\nselect lower(&#8216;I\u011eDIR\u0131\u011fd\u0131r\u0130BRAH\u0130M&#8217;) from dual;<br \/>\nselect &#8216;ismail&#8217; from dual;<br \/>\nselect replace(&#8216;ismail&#8217;,&#8217;i&#8217;,&#8217;\u0130&#8217;) from dual;<br \/>\nfrom personel<br \/>\nwhere upper(lower(ad))=upper(lower(&#8216;omer&#8217;))<br \/>\nwhere increase(ad)=increase(&#8216;omer&#8217;)[\/crayon]<br \/>\nThe following calculates the statistics of the tables and the indexes of the users who run it.<br \/>\n[crayon]create or replace procedure calculate_table_statistics is<br \/>\ncursor c_table is<br \/>\nselect table_name<br \/>\nfrom user_tables;<br \/>\nbegin<br \/>\nfor r_table in c_table<br \/>\nloop<br \/>\nexecute immediate &#8216;analyze table &#8216; || r_table.table_name || &#8216;compute statistics&#8217;;<br \/>\ndbms_output.put_line(r_table.table_name || &#8216; has been analyzed.&#8217;);<br \/>\nend loop;<br \/>\nend;[\/crayon]<br \/>\nThe code can also be run with: exec calculate_table_statistics<\/p>\n<p>Alternatively, the procedure can be scheduled in the toad application&#8217;s jobs tab. This is shown how in a command line environment with the following code:<br \/>\n[crayon]DECLARE<br \/>\njobno NUMBER;<br \/>\nBEGIN<br \/>\nDBMS_JOB.submit<br \/>\n(job =&gt; jobno,<br \/>\nwhat =&gt; &#8216;HR.CALCULATE_TABLE_STATISTICS;&#8217;,<br \/>\nnext_date =&gt; trunc(sysdate)+23\/24,<br \/>\ninterval =&gt; &#8216;SYSDATE + 1&#8217;,<br \/>\nno_parse =&gt; TRUE );<br \/>\nDBMS_OUTPUT.put_line (&#8216;Created Job &#8211; the job number is:&#8217; || TO_CHAR (jobno));<br \/>\nCOMMIT;<br \/>\nEND;<br \/>\n\/[\/crayon]<br \/>\nNote: If a table hs been created using &#8220;create table xxxxx as select * from yyy&#8221;, then its constraints cant be migrated.<\/p>\n<p>The indexes get the table record count from user_tables.<\/p>\n<p>Insert Stress<br \/>\n[crayon]begin<br \/>\nfor i in 1..5<br \/>\nloop<br \/>\ninsert into emp2<br \/>\nselect * from emp2 ;<br \/>\ncommit;<br \/>\nend loop ;<br \/>\nend;[\/crayon]<br \/>\nThis procedure is to compare the row counts between the tables in a schema.<br \/>\n[crayon]Create or replace procedure compare_row_count is<br \/>\ncursor c_table is<br \/>\nselect table_name, num_rows<br \/>\nfrom user_tables;<br \/>\noracle_count number;<br \/>\nactual_count number;<br \/>\nbegin<br \/>\ndbms_output.put_line(&#8216;ACTUAL ORACLE&#8217;);<br \/>\ndbms_output.put_line(&#8216;&#8212;&#8212; &#8212;&#8212;&#8216;);<br \/>\nfor r_table in c_table<br \/>\nloop<br \/>\noracle_count := r_table.num_rows;<br \/>\nexecute immediate &#8216;select count(*) from &#8216; ||r_table.table_name into actual_count;<br \/>\nif (oracle_count = actual_count) then<br \/>\nnull;<br \/>\n&#8212; dbms_output.put_line(r_table.table_name||&#8217;-&#8216;||actual_count||<br \/>\n&#8212; &#8216;*****&#8217;||r_table.table_name||&#8217;-&#8216;||oracle_count);<br \/>\nelse<br \/>\ndbms_output.put_line(&#8216;Attention : &#8216;|| r_table.table_name||&#8217;-&#8216;||actual_count||<br \/>\n&#8216;********&#8217;||r_table.table_name||&#8217;-&#8216;||oracle_count);<br \/>\nend if ;<br \/>\nend loop;<br \/>\nend;[\/crayon]<br \/>\nNote: &#8216;is&#8217; and &#8216;as&#8217; are both supported. Writing &#8216;end procedure&#8217; is also optional.<\/p>\n<p>in &amp; out<br \/>\n[crayon]create or replace procedure get_emp_name_surname<br \/>\n(p_employee_id number, name out varchar2, surname out varchar2, salary out number) is &#8212; (p_employee_id in number, ) not having &#8216;in&#8217; is interpreted the same as having &#8216;in&#8217;. i.e. optional<br \/>\nbegin<br \/>\nselect first_name, last_name, salary<br \/>\ninto name, surname, salary<br \/>\nfrom employees<br \/>\nwhere employee_id = p_employee_id ;<br \/>\nend ;[\/crayon]<br \/>\nThe syntax below can also be run with SQLPlus<br \/>\n[crayon]variable name varchar2(20)<br \/>\nvariable surname varchar2(20) &#8212; both of these are in SQLPlus and probably won&#8217;t work in toad<br \/>\nexec easg(206, :name, :surname); &#8212; easg retrieves both name and surname<br \/>\nprint name<br \/>\nprint surname<br \/>\ncreate synonym easg for get_emp_name_surname<br \/>\ndeclare<br \/>\nname varchar2(20);<br \/>\nsurname varchar2(20);<br \/>\nsalary number;<br \/>\nbegin<br \/>\neasg(206, name, surname, salary); &#8212; Colons are used to retrieve variables declared in SQLPlus which is why they havent been used here.<br \/>\ndbms_output.put_line(name||&#8217; &#8216;||surname||&#8217; &#8216;||salary);<br \/>\nend;[\/crayon]<br \/>\nThe advantage of using a Procedure over a Function: A function can only retrieve a single value, e.g. only name, only surname, single token name_surname but not two separate values.<\/p>\n<p>A function can&#8217;t, for example, retrieve a name and assign it to a variable. However this is possible with a procedure.<\/p>\n<p>Functions can either be a varchar2 or a number type. Procedures are able to simultaneously output multiple variables and types.<\/p>\n<p>Both functions and procedures are considered to be program units. Only execute privileges are granted to these program units.<br \/>\n[crayon]grant execute on raise_salary to student01;[\/crayon]<br \/>\nErrors that could be caused by creating functions and procedures.<br \/>\n[crayon]show errors &#8212; to view errors<br \/>\nselect * from user_errors &#8212; an alternative way of viewing errors<br \/>\nshow errors procedure raise_salary &#8212; if there are many errors[\/crayon]<br \/>\nCompile\/Recompile<br \/>\n[crayon]alter procedure raise_salary compile ;<br \/>\nalter function raise_salary compile ;[\/crayon]<br \/>\nNote: With 10G, the dbms attempts to recompile called program routines that have become invalid.<br \/>\n[crayon]select object_name, status<br \/>\nfrom user_objects<br \/>\ndrop procedure raise_salary ;<br \/>\ndrop function salary_valid ;<br \/>\ndrop type name ;<br \/>\nselect * from<br \/>\nfrom user_objects<br \/>\nwhere object_type=&#8217;PROCEDURE'[\/crayon]<br \/>\nThis code can be viewed in toad. If toad hasnt been installed, it can be viewed using user_source view\/table.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Procedure<\/p>\n","protected":false},"author":1,"featured_media":3498,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[356],"tags":[],"class_list":["post-2881","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pl-sql"],"_links":{"self":[{"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/posts\/2881","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/comments?post=2881"}],"version-history":[{"count":0,"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/posts\/2881\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sysdba.org\/en\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/media?parent=2881"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/categories?post=2881"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sysdba.org\/en\/wp-json\/wp\/v2\/tags?post=2881"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}