Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Venkateswara Reddy.

Asked: June 05, 2002 - 2:02 pm UTC

Last updated: July 09, 2002 - 2:05 pm UTC

Version: 8.1.5

Viewed 1000+ times

You Asked

Hi Tom

Here one more query.

I have a table like

dir_name varchar2(100)
file_name varchar2(50)
extn varchar2(10);

I have some data inthis table. This contains one directory and exisiting files with extnsion like .doc,.xls,.sql on a particular directory. Here I want query like

Total Files *.docfls *.xlsFiles *.sqlFiles *.fmb'Fl
c:\hrms\docs 20 10 5 5
c:\hrms\forms 22 22

some thing like this, If system found new extenstion in a particular directory the query has form like above contain format.

How can I do that. Any help highly appreciated.

Thanks in Advance

Reddy

and Tom said...

You need to dynamically generate that query unless you have a fixed set of file extensions.

The query you will generate will look like this:


select dir_name,
count(*),
sum( decode( extn, 'doc', 1, 0 ) ) docfls,
sum( decode( extn, 'xls', 1, 0 ) ) xlsfls,
sum( decode( extn, 'sql', 1, 0 ) ) sqlfls,
.....
sum( decode( extn, 'fmb', 1, 0 ) ) fmbfls
from t
group by dir_name
/

A stored procedure that will do this is:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( dir_name varchar2(100), file_name varchar2(50), extn varchar2(10) );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> declare
2 type array is table of varchar2(50);
3
4 l_dir_names array := array( 'c:\hrms\docs', 'c:\hrms\forms' );
5 l_dir_cnt number default l_dir_names.count;
6 l_extns array := array( 'doc', 'xls', 'sql', 'fmb', 'txt' );
7 l_extn_cnt number default l_extns.count;
8 begin
9 for i in 1 .. 1000
10 loop
11 insert into t values
12 ( l_dir_names(dbms_random.value( 1, l_dir_cnt ) ),
13 null,
14 l_extns( dbms_random.value( 1, l_extn_cnt ) ) );
15 end loop;
16 commit;
17 end;
18 /

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package demo_pkg
2 as
3 type rc is ref cursor;
4
5 procedure get_cursor( p_cursor in out rc );
6 end;
7 /

Package created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package body demo_pkg
2 as
3
4
5 procedure get_cursor( p_cursor in out rc )
6 is
7 l_query long := 'select dir_name, count(*)';
8 begin
9 for x in ( select distinct extn from t )
10 loop
11 l_query := l_query || ',sum(decode(extn,'''||x.extn||''',1,0)) ' || x.extn || 'fls';
12 end loop;
13 l_query := l_query || ' from t group by dir_name';
14
15 open p_cursor for l_query;
16 end;
17
18 end;
19 /

Package body created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> set autoprint on
ops$tkyte@ORA817DEV.US.ORACLE.COM> variable x refcursor
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec demo_pkg.get_cursor( :x );

PL/SQL procedure successfully completed.


DIR_NAME COUNT(*) DOCFLS FMBFLS SQLFLS TXTFLS XLSFLS
------------- ---------- ---------- ---------- ---------- ---------- ----------
c:\hrms\docs 504 72 113 117 70 132
c:\hrms\forms 496 64 122 118 58 134

ops$tkyte@ORA817DEV.US.ORACLE.COM>



Rating

  (7 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Statistics

Reddy, June 06, 2002 - 12:42 pm UTC

Nice Solution. But, In my table N no of extensions may there. In a particular directory contains many extensions. The query should give when i execute that N no of count of files. I donot want to specify the Extension name such as .XLS,.DOC,.FMB. But above specfied format should come.Here if any new extension found in that table like .DLL, .qry or .vbp the query shoudl take care.

Thanks in advance

Reddy

Tom Kyte
June 06, 2002 - 4:33 pm UTC

I don't believe you read the answer. Read it again.

There is a static query that shows the ONLY way to do this in sql (by hardcoding the values) followed by a stored procedure that dynamically generates the query with any and all of the values it finds in the table -- "if any new extension is found" -- the stored procedure returning a ref cursor will supply it.

There isn't another way to do this with rows and columns -- period.

Statistics

Reddy, June 06, 2002 - 12:48 pm UTC

Nice Solution. But, In my table N no of extensions may there. In a particular directory contains many extensions. The query should give when i execute that N no of count of files. I donot want to specify the Extension name such as .XLS,.DOC,.FMB. But above specfied format should come.Here if any new extension found in that table like .DLL, .qry or .vbp the query shoudl take care.

Thanks in advance

Reddy

statistics

Reddy, June 08, 2002 - 2:05 pm UTC

Thank you Mr. Tom

I have created successfully package and package body. But when I execute the following error occured.

Error at line No : 1
ORA-06512 : Invalid Number
ORA-06512 : at line number 12

I have changed instead of Long Data type to Varchar2(2000), then it says Numeric or Value arror at line number 12.

My database is 8.1.5 Standard Edition.

Thanks in advance

Reddy

Tom Kyte
June 08, 2002 - 5:35 pm UTC

why would you change the length of a string in response to "invalid number"????

Anyway, my line 12 is a "end loop".  what is YOUR line 12 (after putting the string BACK to long so as to get back to the original error, instead of the self induced error of "string too small" you have).

What modifications to my code did you make?  perhaps you should post a complete example we can all run (in the manner of my example)

did you run my example "as is" -- this block:

ops$tkyte@ORA815.US.ORACLE.COM> declare
  2      type array is table of varchar2(50);
  3  
  4      l_dir_names  array := array( 'c:\hrms\docs', 'c:\hrms\forms' );
  5      l_dir_cnt    number default l_dir_names.count;
  6      l_extns      array := array( 'doc', 'xls', 'sql', 'fmb', 'txt' );
  7      l_extn_cnt   number default l_extns.count;
  8  begin
  9      for i in 1 .. 1000
 10      loop
 11          insert into t values
 12          ( l_dir_names(mod( i, l_dir_cnt ) +1 ),
 13            null,
 14            l_extns( mod(i, l_extn_cnt ) +1 ) );
 15      end loop;
 16      commit;
 17  end;
 18  /

will generate test data for you in 815 (i ran this test in 815, my code works fine, must be some modification you added to my code, or some difference in the reality of your tables and the tables you discussed in the question)

 

Tuning scripts

Andre, June 10, 2002 - 12:09 pm UTC

Do you have some personal collection of scripts you might make available to us ? My main interest is tuning scripts reflecting much of what is discussed on this site.

Tom Kyte
June 11, 2002 - 10:07 am UTC

for general tuning I use statspack.

For tuning tuning -- well, I typically start from scratch. Yes -- from scratch.

I find most issues are "unique" (if they are not, statspack picks up on it for me). I develop scripts for the site I'm at -- and find they are not generally reusable.

So -- sorry, I don't have a directory full of tuning scripts. utllockt, statsback (estat/bstat before that) and tkprof are my main tools.

STATISTICS

Reddy, June 12, 2002 - 6:38 am UTC

Hi tom
Please look up this code and tell me where exactly wrong is there.

scott@PSI1> ED
Wrote file afiedt.buf

1 Create or Replace package demo_pkg
2 as
3 type rc is ref cursor;
4 procedure get_cursor( p_cursor in out rc );
5* end;
scott@PSI1> /

Package created.

scott@PSI1> ed
Wrote file afiedt.buf

1 Create or Replace package body demo_pkg
2 as
3 procedure get_cursor( p_cursor in out rc )
4 is
5 l_query LONG := 'select directory_name, count(*)';
6 begin
7 for x in ( select distinct extn from VC_DIR_STS_TBL )
8 loop
9 l_query := l_query || ',SUM(decode(extn,'''||x.extn||''',1,0)) ' || x.extn || 'fls';
10 end loop;
11 l_query := l_query || ' from VC_DIR_STS_TBL group by directory_name';
12 open p_cursor for l_query;
13 end;
14* end;
15 /

Package body created.

scott@PSI1> desc VC_DIR_STS_TBL
Name Null? Type
------------------------------- -------- ----
DIRECTORY_NAME VARCHAR2(500)
FILE_NAME VARCHAR2(1000)
EXTN VARCHAR2(10)

scott@PSI1> serveroutput OFF
serveroutput OFF
linesize 80
set autoprint on
scott@PSI1> variable x refcursor
scott@PSI1> exec demo_pkg.get_cursor(:x);
begin demo_pkg.get_cursor(:x); end;

*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at "SCOTT.DEMO_PKG", line 12
ORA-06512: at line 1


scott@PSI1> spool off
Thanks in advance

Reddy

Tom Kyte
June 12, 2002 - 7:26 am UTC

time for you to do some debugging,  use a procedure like:

create or replace procedure p ( p_str in varchar2 )
is
   l_str   long := p_str;
begin
   loop
      exit when l_str is null;
      dbms_output.put_line( substr( l_str, 1, 250 ) );
      l_str := substr( l_str, 251 );
   end loop;
end;
/

to print out the query and run the query standalone in sqlplus.  I cannot  reproduce.  I just:

ops$tkyte@ORA815.US.ORACLE.COM> create table vc_dir_sts_tbl (directory_name varchar2(10), file_name varchar2(10), extn varchar2(10) );

Table created.

ops$tkyte@ORA815.US.ORACLE.COM> insert into vc_dir_sts_tbl select substr(username,1,10), substr(username,1,10), substr(username,1,3) from all_users;

14 rows created.

ops$tkyte@ORA815.US.ORACLE.COM> Create or Replace package demo_pkg
  2   as
  3       type rc is ref cursor;
  4       procedure get_cursor( p_cursor in out rc );
  5   end;
  6  /

Package created.

ops$tkyte@ORA815.US.ORACLE.COM> Create or Replace package body demo_pkg
  2  as
  3  procedure get_cursor( p_cursor in out rc )
  4  is
  5      l_query LONG := 'select directory_name, count(*)';
  6  begin
  7      for x in ( select distinct extn from VC_DIR_STS_TBL )
  8     loop
  9        l_query := l_query || ',SUM(decode(extn,'''||x.extn||''',1,0)) ' || x.extn || 'fls';
 10     end loop;
 11     l_query := l_query || ' from VC_DIR_STS_TBL group by directory_name';
 12     p(l_query);
 13     open p_cursor for l_query;
 14  end;
 15  end;
 16  /

Package body created.

ops$tkyte@ORA815.US.ORACLE.COM> 
ops$tkyte@ORA815.US.ORACLE.COM> variable x refcursor
ops$tkyte@ORA815.US.ORACLE.COM> exec demo_pkg.get_cursor(:x);
select directory_name, count(*),SUM(decode(extn,'A',1,0)) Afls,SUM(decode(extn,'AUR',1,0)) AURfls,SUM(decode(extn,'B',1,0))
Bfls,SUM(decode(extn,'DBS',1,0)) DBSfls,SUM(decode(extn,'DEV',1,0)) DEVfls,SUM(decode(extn,'GSC',1,0)) GSCfls,SUM(decode(extn,
'OPS',1,0)) OPSfls,SUM(decode(extn,'OUT',1,0)) OUTfls,SUM(decode(extn,'SCO',1,0)) SCOfls,SUM(decode(extn,'SYS',1,0))
SYSfls,SUM(decode(extn,'USE',1,0)) USEfls from VC_DIR_STS_TBL group by directory_name

PL/SQL procedure successfully completed.

ops$tkyte@ORA815.US.ORACLE.COM> print x

DIRECTORY_   COUNT(*)       AFLS     AURFLS       BFLS     DBSFLS     DEVFLS     GSCFLS     OPSFLS     OUTFLS     SCOFLS     SYSFLS
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    USEFLS
----------
A                   1          1          0          0          0          0          0          0          0          0          0
         0         0          0          0          0          0
         0


Take the query produced in text and run it and see what happens.  This method 

a) works
b) works well
c) works in 815

<b>update on this one... just figured it out.  You have an extn that isn't a valid identifier in Oracle...</b>

consider:

ops$tkyte@ORA815.US.ORACLE.COM> insert into vc_dir_sts_tbl values ( 3, 3, 3 );

1 row created.

ops$tkyte@ORA815.US.ORACLE.COM> variable x refcursor
ops$tkyte@ORA815.US.ORACLE.COM> exec demo_pkg.get_cursor(:x);
select directory_name, count(*),SUM(decode(extn,'3',1,0)) 3fls,SUM(decode(extn,'A',1,0)) Afls,SUM(decode(extn,'AUR',1,0))
AURfls,SUM(decode(extn,'B',1,0)) Bfls,SUM(decode(extn,'DBS',1,0)) DBSfls,SUM(decode(extn,'DEV',1,0)) DEVfls,SUM(decode(extn,'GSC
',1,0)) GSCfls,SUM(decode(extn,'OPS',1,0)) OPSfls,SUM(decode(extn,'OUT',1,0)) OUTfls,SUM(decode(extn,'SCO',1,0))
SCOfls,SUM(decode(extn,'SYS',1,0)) SYSfls,SUM(decode(extn,'USE',1,0)) USEfls from VC_DIR_STS_TBL group by directory_name
BEGIN demo_pkg.get_cursor(:x); END;

*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at "OPS$TKYTE.DEMO_PKG", line 13
ORA-06512: at line 1


there is your error , it is caused by this "SUM(decode(extn,'3',1,0)) 3fls"

solution:

  9        l_query := l_query || ',SUM(decode(extn,'''||x.extn||''',1,0)) "' || x.extn || 'fls"';


use QUOTED identifiers (with double quotes).   that'll do it. 

Statistics

R.V.Reddy, June 13, 2002 - 1:01 pm UTC

Dear Tom

I have taken same code and executed, but again failed says that 'P'Must be declared. I am
not able debug. I show my development team also, they are unable to find what is wrong. Here
what is the reason to add ' P(l_query) '. Can you explain plese?


scott@PSI1> Create or Replace package demo_pkg
2 as
3 type rc is ref cursor;
4 procedure get_cursor( p_cursor in out rc );
5 end;
6 /

Package created.

scott@PSI1> Create or Replace package body demo_pkg
2 as
3 procedure get_cursor( p_cursor in out rc )
4 is
5 l_query LONG := 'select directory_name, count(*)';
6 begin
7 for x in ( select distinct extn from VC_DIR_STS_TBL )
8 loop
9 l_query := l_query || ',SUM(decode(extn,'''||x.extn||''',1,0)) "' ||
10 x.extn || 'fls"';
11 end loop;
12 l_query := l_query || ' from VC_DIR_STS_TBL group by directory_name';
13 p(l_query);
14 open p_cursor for l_query;
15 end;
16* end;
17 /

Warning: Package Body created with compilation errors.

scott@PSI1> SHOW ERRORS
No errors.
scott@PSI1> SELECT TEXT,LINE,POSITION FROM USER_ERRORS WHERE NAME='DEMO_PKG';

TEXT
--------------------------------------------------------------------------------
LINE POSITION
---------- ----------
PLS-00201: identifier 'P' must be declared
13 7

PL/SQL: Statement ignored
13 7


scott@PSI1> SPOOL OFF
Thanks in advance

Reddy

Tom Kyte
June 13, 2002 - 1:06 pm UTC

reread the followup right above this one

a) p is a procedure I wrote and supplied for you there.
b) I found out what the error was and came back and updated the followup. I debugged it for you. Answer supplied above.

A reader, July 09, 2002 - 2:05 pm UTC

Reddy,

Better quit job...go home and study Oracle Manual

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library